From 685782224bac2f64417e9532105e3c061002d620 Mon Sep 17 00:00:00 2001 From: rharding6373 Date: Tue, 9 May 2023 22:32:23 -0700 Subject: [PATCH] sql: fix record-returning udfs with no result Previously, record-returning UDFs whose last SQL statement returned no result (i.e., not a SELECT or RETURNING statement) would succeed. They now return a return type mismatch error, as expected. Epic: CRDB-19255 Informs: #87289 Release note: None --- pkg/sql/logictest/testdata/logic_test/udf_insert | 5 ++--- pkg/sql/opt/optbuilder/create_function.go | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/udf_insert b/pkg/sql/logictest/testdata/logic_test/udf_insert index 82c51997b731..157113cde510 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_insert +++ b/pkg/sql/logictest/testdata/logic_test/udf_insert @@ -1,9 +1,8 @@ statement ok CREATE TABLE t (a INT PRIMARY KEY, b INT DEFAULT 0); -# TODO: UDFs should always return results. -statement ok -CREATE FUNCTION f_should_err() RETURNS RECORD AS +statement error pq: return type mismatch in function declared to return record\nDETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING. +CREATE FUNCTION f_err() RETURNS RECORD AS $$ INSERT INTO t VALUES (1,2); $$ LANGUAGE SQL; diff --git a/pkg/sql/opt/optbuilder/create_function.go b/pkg/sql/opt/optbuilder/create_function.go index af5df96de26d..72697c5e6fbf 100644 --- a/pkg/sql/opt/optbuilder/create_function.go +++ b/pkg/sql/opt/optbuilder/create_function.go @@ -239,10 +239,6 @@ func validateReturnType(expected *types.T, cols []scopeColumn) error { if expected.Equivalent(types.Void) { return nil } - // If return type is RECORD, any column types are valid. - if types.IsRecordType(expected) { - return nil - } if len(cols) == 0 { return pgerror.WithCandidateCode( @@ -254,6 +250,11 @@ func validateReturnType(expected *types.T, cols []scopeColumn) error { ) } + // If return type is RECORD, any column types are valid. + if types.IsRecordType(expected) { + return nil + } + if len(cols) == 1 { if !expected.Equivalent(cols[0].typ) && !cast.ValidCast(cols[0].typ, expected, cast.ContextAssignment) {