Skip to content

Commit

Permalink
sql: implement function OID reference
Browse files Browse the repository at this point in the history
This commit implements `[FUNCTION xxxx]` OID references syntax
of functions. With this change, functions can be called with
the new OID numerical representation. For example
`SELECT [FUNCTION 123]('helloworld')`. The intention of this
syntax is only for internal serialization of references to UDFs.
But it's general enough for builtin functions as well.

A new implementation of the `ResolvableFunctionReference`
interface, `OIDFunctionReference` is introduced for function
resolution purpose for the new syntax.

The `ResolveFunctionByOID` method is also refactored to return
a qualified name.

Fixes: cockroachdb#83231

Release note: None
  • Loading branch information
chengxiong-ruan committed Feb 14, 2023
1 parent 47331b1 commit 41e5e6a
Show file tree
Hide file tree
Showing 28 changed files with 454 additions and 97 deletions.
30 changes: 17 additions & 13 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -3495,11 +3495,11 @@ opt_interval_qualifier ::=
|

func_application ::=
func_name '(' ')'
| func_name '(' expr_list opt_sort_clause ')'
| func_name '(' 'ALL' expr_list opt_sort_clause ')'
| func_name '(' 'DISTINCT' expr_list ')'
| func_name '(' '*' ')'
func_application_name '(' ')'
| func_application_name '(' expr_list opt_sort_clause ')'
| func_application_name '(' 'ALL' expr_list opt_sort_clause ')'
| func_application_name '(' 'DISTINCT' expr_list ')'
| func_application_name '(' '*' ')'

within_group_clause ::=
'WITHIN' 'GROUP' '(' single_sort_clause ')'
Expand Down Expand Up @@ -3751,10 +3751,9 @@ rowsfrom_item ::=
opt_col_def_list ::=
'(' col_def_list ')'

func_name ::=
type_function_name
| prefixed_column_path
| 'INDEX'
func_application_name ::=
func_name
| '[' 'FUNCTION' iconst32 ']'

single_sort_clause ::=
'ORDER' 'BY' sortby
Expand Down Expand Up @@ -3902,10 +3901,10 @@ create_as_params ::=
col_def_list ::=
( col_def ) ( ( ',' col_def ) )*

type_function_name ::=
'identifier'
| unreserved_keyword
| type_func_name_keyword
func_name ::=
type_function_name
| prefixed_column_path
| 'INDEX'

opt_existing_window_name ::=
name
Expand Down Expand Up @@ -3946,6 +3945,11 @@ trim_list ::=
| 'FROM' expr_list
| expr_list

type_function_name ::=
'identifier'
| unreserved_keyword
| type_func_name_keyword

char_aliases ::=
'CHAR'
| 'CHARACTER'
Expand Down
8 changes: 4 additions & 4 deletions pkg/ccl/changefeedccl/cdceval/func_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ func (rs *cdcFunctionResolver) ResolveFunction(
// ResolveFunctionByOID implements FunctionReferenceResolver interface.
func (rs *cdcFunctionResolver) ResolveFunctionByOID(
ctx context.Context, oid oid.Oid,
) (string, *tree.Overload, error) {
) (*tree.FunctionName, *tree.Overload, error) {
fnName, overload, err := rs.wrapped.ResolveFunctionByOID(ctx, oid)
if err != nil {
return "", nil, err
return nil, nil, err
}
if err := checkOverloadSupported(fnName, overload); err != nil {
return "", nil, err
if err := checkOverloadSupported(fnName.Object(), overload); err != nil {
return nil, nil, err
}
return fnName, overload, err
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/sql/faketreeeval/evalctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ func (ep *DummyEvalPlanner) ResolveFunction(
// ResolveFunctionByOID implements FunctionReferenceResolver interface.
func (ep *DummyEvalPlanner) ResolveFunctionByOID(
ctx context.Context, oid oid.Oid,
) (string, *tree.Overload, error) {
return "", nil, errors.AssertionFailedf("ResolveFunctionByOID unimplemented")
) (*tree.FunctionName, *tree.Overload, error) {
return nil, nil, errors.AssertionFailedf("ResolveFunctionByOID unimplemented")
}

// GetMultiregionConfig is part of the eval.Planner interface.
Expand Down
4 changes: 2 additions & 2 deletions pkg/sql/importer/import_table_creation.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,6 @@ func (r fkResolver) ResolveFunction(
// ResolveFunctionByOID implements the resolver.SchemaResolver interface.
func (r fkResolver) ResolveFunctionByOID(
ctx context.Context, oid oid.Oid,
) (string, *tree.Overload, error) {
return "", nil, errSchemaResolver
) (*tree.FunctionName, *tree.Overload, error) {
return nil, nil, errSchemaResolver
}
134 changes: 134 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/udf_oid_ref
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# 1074 is the OID of builtin function "string_to_array" with signature
# "string_to_array(str: string, delimiter: string) -> string[]".
query T
SELECT [FUNCTION 1074]('hello,world', ',')
----
{hello,world}

statement ok
CREATE TABLE t1(a INT PRIMARY KEY, b STRING DEFAULT ([FUNCTION 1074]('hello,world', ',')))

statement ok
INSERT INTO t1(a) VALUES (1)

query IT
SELECT * FROM t1
----
1 {hello,world}

statement ok
INSERT INTO t1 VALUES (2, 'hello,new,world')

statement ok
CREATE INDEX idx ON t1([FUNCTION 1074](b,','))

query IT
SELECT * FROM t1@idx WHERE [FUNCTION 1074](b, ',') = ARRAY['hello','new','world']
----
2 hello,new,world

# 814 is the OID of builtin function "length" with signature
# "length(val: string) -> int".
statement ok
ALTER TABLE t1 ADD CONSTRAINT c_len CHECK ([FUNCTION 814](b) > 2)

statement error pq: failed to satisfy CHECK constraint \(length\(b\) > 2:::INT8\)
INSERT INTO t1 VALUES (3, 'a')

statement ok
CREATE FUNCTION f1() RETURNS INT LANGUAGE SQL AS $$ SELECT 1 $$

let $fn_oid
SELECT oid FROM pg_catalog.pg_proc WHERE proname = 'f1'

query I
SELECT [FUNCTION $fn_oid]()
----
1

statement ok
CREATE FUNCTION f2(a STRING) RETURNS STRING LANGUAGE SQL AS $$ SELECT a $$

let $fn_oid
SELECT oid FROM pg_catalog.pg_proc WHERE proname = 'f2'

query T
SELECT [FUNCTION $fn_oid]('hello world')
----
hello world

# Make sure that argument types are still checked even we know which function
# overload to use.
statement error pq: unknown signature: f2\(int\)
SELECT [FUNCTION $fn_oid](123)

# Make sure that renaming does not break the reference.
statement ok
ALTER FUNCTION f2(STRING) RENAME TO f2_new;

query T
SELECT [FUNCTION $fn_oid]('hello world')
----
hello world

statement ok
CREATE SCHEMA sc1;

statement ok
ALTER FUNCTION f2_new(STRING) SET SCHEMA sc1;

query T
SELECT [FUNCTION $fn_oid]('hello world')
----
hello world

# Make sure that function dropped cannot be resolved.
statement ok
DROP FUNCTION sc1.f2_new(STRING);

statement error function undefined
SELECT [FUNCTION $fn_oid]('maybe')

# Referencing UDF OID within a UDF

statement ok
CREATE FUNCTION f_in_udf() RETURNS INT LANGUAGE SQL AS $$ SELECT 1 $$;

let $fn_oid
SELECT oid FROM pg_catalog.pg_proc WHERE proname = 'f_in_udf'

# TODO(chengxiong,mgartner): Fix this test when we enable support of calling UDFs from UDFs.
statement error pq: function \d+ not found: function undefined
CREATE FUNCTION f_using_udf() RETURNS INT LANGUAGE SQL AS $$ SELECT [FUNCTION $fn_oid]() $$;

# 814 is the OID of builtin function "length" with signature, and it's ok to
# call it from a UDF.
statement ok
CREATE FUNCTION f_using_udf() RETURNS INT LANGUAGE SQL AS $$ SELECT [FUNCTION 814]('abc') $$;

query I
SELECT f_using_udf();
----
3

# Make sure cross-db reference by OID is ok

statement ok
CREATE DATABASE db1

statement ok
USE db1

statement ok
CREATE FUNCTION f_cross_db() RETURNS INT LANGUAGE SQL AS $$ SELECT 321 $$;

let $fn_oid
SELECT oid FROM pg_catalog.pg_proc WHERE proname = 'f_cross_db'

statement ok
USE test

query I
SELECT [FUNCTION $fn_oid]()
----
321
7 changes: 7 additions & 0 deletions pkg/sql/logictest/tests/fakedist-disk/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/sql/logictest/tests/fakedist/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/sql/logictest/tests/local-vec-off/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/sql/logictest/tests/local/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/sql/opt/cat/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ type Catalog interface {
) (*tree.ResolvedFunctionDefinition, error)

// ResolveFunctionByOID resolves a function overload by OID.
ResolveFunctionByOID(ctx context.Context, oid oid.Oid) (string, *tree.Overload, error)
ResolveFunctionByOID(ctx context.Context, oid oid.Oid) (*tree.FunctionName, *tree.Overload, error)

// CheckPrivilege verifies that the current user has the given privilege on
// the given catalog object. If not, then CheckPrivilege returns an error.
Expand Down
4 changes: 2 additions & 2 deletions pkg/sql/opt/testutils/testcat/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func (tc *Catalog) ResolveFunction(
// ResolveFunctionByOID part of the tree.FunctionReferenceResolver interface.
func (tc *Catalog) ResolveFunctionByOID(
ctx context.Context, oid oid.Oid,
) (string, *tree.Overload, error) {
return "", nil, errors.AssertionFailedf("ResolveFunctionByOID not supported in test catalog")
) (*tree.FunctionName, *tree.Overload, error) {
return nil, nil, errors.AssertionFailedf("ResolveFunctionByOID not supported in test catalog")
}

// CreateFunction handles the CREATE FUNCTION statement.
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/opt_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func (oc *optCatalog) ResolveFunction(

func (oc *optCatalog) ResolveFunctionByOID(
ctx context.Context, oid oid.Oid,
) (string, *tree.Overload, error) {
) (*tree.FunctionName, *tree.Overload, error) {
return oc.planner.ResolveFunctionByOID(ctx, oid)
}

Expand Down
Loading

0 comments on commit 41e5e6a

Please sign in to comment.