From e4ccbcf1673e6562d7c6d6203d015697d7382ab3 Mon Sep 17 00:00:00 2001 From: Faizan Qazi Date: Thu, 22 Feb 2024 18:06:26 -0500 Subject: [PATCH] sql: enable support for udfs calling other udfs 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: #88198 Release note: None --- pkg/sql/logictest/testdata/logic_test/procedure | 2 +- pkg/sql/logictest/testdata/logic_test/udf_oid_ref | 7 +++---- pkg/sql/logictest/testdata/logic_test/udf_unsupported | 6 +++--- pkg/sql/opt/optbuilder/create_function.go | 6 ------ 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/procedure b/pkg/sql/logictest/testdata/logic_test/procedure index 304fe031880e..11c3f9a392d1 100644 --- a/pkg/sql/logictest/testdata/logic_test/procedure +++ b/pkg/sql/logictest/testdata/logic_test/procedure @@ -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 diff --git a/pkg/sql/logictest/testdata/logic_test/udf_oid_ref b/pkg/sql/logictest/testdata/logic_test/udf_oid_ref index 166d878735f1..3842256d167c 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_oid_ref +++ b/pkg/sql/logictest/testdata/logic_test/udf_oid_ref @@ -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 diff --git a/pkg/sql/logictest/testdata/logic_test/udf_unsupported b/pkg/sql/logictest/testdata/logic_test/udf_unsupported index ac57af5bf086..f20467fe2bab 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_unsupported +++ b/pkg/sql/logictest/testdata/logic_test/udf_unsupported @@ -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(); @@ -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 diff --git a/pkg/sql/opt/optbuilder/create_function.go b/pkg/sql/opt/optbuilder/create_function.go index 45a47f7b4a59..e750909f1c59 100644 --- a/pkg/sql/opt/optbuilder/create_function.go +++ b/pkg/sql/opt/optbuilder/create_function.go @@ -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. @@ -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.