Skip to content

Commit

Permalink
sql: disallow UDFs with CTES and subqueries
Browse files Browse the repository at this point in the history
UDFs with CTEs and subqueries are not supported. This commit makes it
impossible to create them.

This commit also adds additional tests to ensure that UDFs with DDL,
mutations, and prepared statements are not allowed.

Release note: None
  • Loading branch information
mgartner committed Sep 23, 2022
1 parent 975701e commit c7aabd4
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
68 changes: 66 additions & 2 deletions pkg/sql/logictest/testdata/logic_test/udf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
statement ok
CREATE TABLE ab (
a INT PRIMARY KEY,
b INT
a INT PRIMARY KEY,
b INT
)

statement error pq: unimplemented: user-defined functions with SETOF return types are not supported
Expand Down Expand Up @@ -2151,3 +2151,67 @@ a text

statement error pgcode 22001 value too long for type CHAR
SELECT stoc('abc')


subtest ddl

# DDL is not currently supported in UDF bodies.
statement error pgcode 0A000 unimplemented: CREATE TABLE usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'CREATE TABLE t (a INT)'

statement error pgcode 0A000 unimplemented: ALTER TABLE usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'ALTER TABLE t ADD COLUMN b BOOL'

statement error pgcode 0A000 unimplemented: DROP TABLE usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'DROP TABLE t'


subtest mutation

# Mutations are not currently supported in UDF bodies.
statement error pgcode 0A000 unimplemented: INSERT usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'INSERT INTO t VALUES (1)'

statement error pgcode 0A000 unimplemented: INSERT usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'UPSERT INTO t VALUES (1)'

statement error pgcode 0A000 unimplemented: UPDATE usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'UPDATE t SET a = 1'

statement error pgcode 0A000 unimplemented: DELETE usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'DELETE FROM t WHERE a = 1'


subtest prepared_statement

# Prepared statements are not currently supported in UDF bodies.
statement error pgcode 0A000 unimplemented: PREPARE usage inside a function definition
CREATE FUNCTION err() RETURNS VOID LANGUAGE SQL AS 'PREPARE p AS SELECT * FROM t'


subtest cte

# CTEs are not currently supported in UDF bodies.
statement error pgcode 0A000 unimplemented: CTE usage inside a function definition
CREATE FUNCTION err() RETURNS INT LANGUAGE SQL AS 'WITH s AS (SELECT a FROM t) SELECT a FROM s'


subtest recursion

# Recursive UDFs are not currently supported.
statement error pgcode 42883 unknown function: rec()
CREATE FUNCTION rec(i INT) RETURNS INT LANGUAGE SQL AS 'SELECT CASE i WHEN 0 THEN 0 ELSE i + rec(i-1) END'

# References to other UDFs in UDF bodies are not currently supported.
statement ok
CREATE FUNCTION other_udf() RETURNS INT LANGUAGE SQL AS 'SELECT 1'

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


subtest subqueries

# UDFs with subqueries are not currently supported.
statement error pgcode 0A000 unimplemented: subquery usage inside a function definition
CREATE FUNCTION rec(i INT) RETURNS INT LANGUAGE SQL AS 'SELECT * FROM t WHERE a = (SELECT max(i) FROM s)'
4 changes: 4 additions & 0 deletions pkg/sql/opt/optbuilder/subquery.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree/treecmp"
"github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
"github.com/cockroachdb/errors"
)

Expand Down Expand Up @@ -202,6 +203,9 @@ func (s *subquery) Eval(_ tree.ExprEvaluator) (tree.Datum, error) {
// It stores the resulting relational expression in s.node, and also updates
// s.cols and s.ordering with the output columns and ordering of the subquery.
func (s *subquery) buildSubquery(desiredTypes []*types.T) {
if s.scope.builder.insideFuncDef {
panic(unimplemented.New("user-defined functions", "subquery usage inside a function definition"))
}
if s.scope.replaceSRFs {
// We need to save and restore the previous value of the replaceSRFs field in
// case we are recursively called within a subquery context.
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/opt/optbuilder/with.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry"
"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
"github.com/cockroachdb/errors"
)

Expand Down Expand Up @@ -128,6 +129,9 @@ func (b *Builder) buildCTEs(
if with == nil {
return inScope, nil
}
if b.insideFuncDef {
panic(unimplemented.New("user-defined functions", "CTE usage inside a function definition"))
}

outScope = inScope.push()
addedCTEs := make([]cteSource, len(with.CTEList))
Expand Down

0 comments on commit c7aabd4

Please sign in to comment.