Skip to content

Commit

Permalink
sql: enable support for udfs calling other udfs
Browse files Browse the repository at this point in the history
Previously, we blocked the ability of one UDF to call another UDF due to
a lack of dependency tracking. This patch removes this limitation by
allowing user-defined functions to reference other user-defined functions
in their bodies.

Informs: cockroachdb#88198
Release note: None
  • Loading branch information
fqazi committed Mar 6, 2024
1 parent 1516e36 commit e4ccbcf
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 14 deletions.
2 changes: 1 addition & 1 deletion pkg/sql/logictest/testdata/logic_test/procedure
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ CREATE OR REPLACE PROCEDURE p2() LANGUAGE SQL AS $$
CALL p();
$$

statement error pgcode 42883 unknown function: p\(\)
statement error pgcode 42809 p\(\) is a procedure
CREATE FUNCTION err(i INT) RETURNS VOID LANGUAGE SQL AS 'SELECT p()'

statement error pgcode 0A000 unimplemented: CALL usage inside a function definition
Expand Down
7 changes: 3 additions & 4 deletions pkg/sql/logictest/testdata/logic_test/udf_oid_ref
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,16 @@ 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 pgcode 42883 pq: function \d+ not found
statement ok
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') $$;
CREATE FUNCTION f_using_udf_2() RETURNS INT LANGUAGE SQL AS $$ SELECT [FUNCTION 814]('abc') $$;

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

Expand Down
6 changes: 3 additions & 3 deletions pkg/sql/logictest/testdata/logic_test/udf_unsupported
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ subtest disallow_udf_in_views_and_udf
statement ok
CREATE FUNCTION test_vf_f() RETURNS STRING LANGUAGE SQL AS $$ SELECT lower('hello') $$;

statement error pgcode 42883 pq: unknown function: test_vf_f\(\)\nHINT:.*intention was to use a user-defined function in the function body, which is currently not supported.
statement ok
CREATE FUNCTION test_vf_g() RETURNS STRING LANGUAGE SQL AS $$ SELECT test_vf_f() $$;

statement ok
CREATE FUNCTION test_vf_g() RETURNS STRING LANGUAGE SQL AS $$ SELECT lower('hello') $$;
CREATE FUNCTION test_vf_g_2() RETURNS STRING LANGUAGE SQL AS $$ SELECT lower('hello') $$;

statement error pgcode 42883 pq: unknown function: test_vf_f\(\)\nHINT:.*intention was to use a user-defined function in the view query, which is currently not supported.
CREATE VIEW v AS SELECT test_vf_f();
Expand Down Expand Up @@ -139,7 +139,7 @@ CREATE FUNCTION rec(i INT) RETURNS INT LANGUAGE SQL AS 'SELECT CASE i WHEN 0 THE
statement ok
CREATE FUNCTION other_udf() RETURNS INT LANGUAGE SQL AS 'SELECT 1'

statement error pgcode 42883 unknown function: other_udf()
statement ok
CREATE FUNCTION err() RETURNS INT LANGUAGE SQL AS 'SELECT other_udf()'

subtest end
Expand Down
6 changes: 0 additions & 6 deletions pkg/sql/opt/optbuilder/create_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o
schID := b.factory.Metadata().AddSchema(sch)
cf.Name.ObjectNamePrefix = resName

// TODO(#88198): this is a hack to disallow UDF usage in UDF and we will
// need to lift this hack when we plan to allow it.
preFuncResolver := b.semaCtx.FunctionResolver
b.semaCtx.FunctionResolver = nil

b.insideFuncDef = true
b.trackSchemaDeps = true
// Make sure datasource names are qualified.
Expand All @@ -70,7 +65,6 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o
b.evalCtx.Annotations = oldEvalCtxAnn
b.semaCtx.Annotations = oldSemaCtxAnn

b.semaCtx.FunctionResolver = preFuncResolver
switch recErr := recover().(type) {
case nil:
// No error.
Expand Down

0 comments on commit e4ccbcf

Please sign in to comment.