Skip to content

Commit

Permalink
sql: allow procedures to call other procedures
Browse files Browse the repository at this point in the history
Release note (sql change): Stored procedures can now invoke other
stored procedures via `CALL` statements.
  • Loading branch information
mgartner committed Mar 18, 2024
1 parent 4d7f62c commit d4c3db5
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 11 deletions.
104 changes: 95 additions & 9 deletions pkg/sql/logictest/testdata/logic_test/procedure
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,9 @@ CALL p(foo())
statement error pgcode 42723 function "p" already exists with same argument types
CREATE FUNCTION p() RETURNS VOID LANGUAGE SQL AS ''

# TODO(mgartner): The error should state "procedure definition" too.
statement error pgcode 0A000 unimplemented: CALL usage inside a function definition
CREATE OR REPLACE PROCEDURE p2() LANGUAGE SQL AS $$
CALL 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
CREATE FUNCTION err(i INT) RETURNS VOID LANGUAGE SQL AS 'CALL p()'

statement error pgcode 42809 p\(\) is a procedure\nHINT: To call a procedure, use CALL.
CREATE TABLE err (i INT DEFAULT p())

Expand Down Expand Up @@ -412,3 +403,98 @@ statement error pgcode 42P13 null input attribute not allowed in procedure defin
CREATE PROCEDURE pv() AS 'SELECT 1' STRICT LANGUAGE SQL;

subtest end

subtest proc_invokes_proc

statement ok
CREATE PROCEDURE a() LANGUAGE SQL AS $$
SELECT 1;
$$

statement ok
CREATE PROCEDURE b() LANGUAGE SQL AS $$
CALL a();
$$

# Mutual recursion is not currently allowed.
statement error pgcode 42P13 cannot add dependency from descriptor \d+ to function b \(\d+\) because there will be a dependency cycle
CREATE OR REPLACE PROCEDURE a() LANGUAGE SQL AS $$
CALL b();
$$

statement error pgcode 2BP01 cannot drop function \"a\" because other objects \(\[test.public.b\]\) still depend on it
DROP PROCEDURE a

statement ok
DROP PROCEDURE b;
DROP PROCEDURE a;

statement ok
CREATE TYPE e AS ENUM ('foo', 'bar');

statement ok
CREATE PROCEDURE a() LANGUAGE SQL AS $$
SELECT 'foo'::e;
$$

statement ok
CREATE PROCEDURE b() LANGUAGE SQL AS $$
CALL a();
$$

statement error pgcode 2BP01 cannot drop type \"e\" because other objects \(\[test.public.a\]\) still depend on it
DROP TYPE e

statement ok
DROP PROCEDURE b;
DROP PROCEDURE a;
DROP TYPE e;

statement ok
CREATE TABLE ab (
a INT PRIMARY KEY,
b INT
)

statement ok
CREATE PROCEDURE ins_ab(new_a INT, new_b INT) LANGUAGE SQL AS $$
INSERT INTO ab VALUES (new_a, new_b);
$$

statement ok
CREATE PROCEDURE ins3() LANGUAGE SQL AS $$
CALL ins_ab(1, 10);
CALL ins_ab(2, 20);
CALL ins_ab(3, 30);
$$

statement ok
CALL ins_ab(4, 40)

statement ok
CALL ins3()

statement error pgcode 23505 duplicate key value violates unique constraint \"ab_pkey\"
CALL ins3()

query II rowsort
SELECT * FROM ab
----
1 10
2 20
3 30
4 40

# TODO(#102771): Add dependency tracking that causes this to error.
# statement error pgcode 2BP01 cannot drop table ab because other objects depend on it
# DROP TABLE ab;

statement error pgcode 2BP01 cannot drop function \"ins_ab\" because other objects \(\[test.public.ins3\]\) still depend on it
DROP PROCEDURE ins_ab

statement ok
DROP PROCEDURE ins3;
DROP PROCEDURE ins_ab;
DROP TABLE ab;

subtest end
9 changes: 7 additions & 2 deletions pkg/sql/opt/optbuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ func (b *Builder) buildStmt(
if !activeVersion.IsActive(clusterversion.V23_2) {
panic(unimplemented.Newf("user-defined functions", "%s usage inside a function definition is not supported until version 23.2", stmt.StatementTag()))
}
case *tree.Call:
activeVersion := b.evalCtx.Settings.Version.ActiveVersion(b.ctx)
if !activeVersion.IsActive(clusterversion.V24_1) {
panic(unimplemented.Newf("user-defined functions", "%s usage inside a function definition is not supported until version 23.2", stmt.StatementTag()))
}
default:
panic(unimplemented.Newf("user-defined functions", "%s usage inside a function definition", stmt.StatementTag()))
}
Expand Down Expand Up @@ -494,7 +499,7 @@ func (b *Builder) trackReferencedColumnForViews(col *scopeColumn) {

func (b *Builder) maybeTrackRegclassDependenciesForViews(texpr tree.TypedExpr) {
if b.trackSchemaDeps {
if texpr.ResolvedType().Identical(types.RegClass) {
if texpr != nil && texpr.ResolvedType().Identical(types.RegClass) {
// We do not add a dependency if the RegClass Expr contains variables,
// we cannot resolve the variables in this context. This matches Postgres
// behavior.
Expand Down Expand Up @@ -528,7 +533,7 @@ func (b *Builder) maybeTrackRegclassDependenciesForViews(texpr tree.TypedExpr) {

func (b *Builder) maybeTrackUserDefinedTypeDepsForViews(texpr tree.TypedExpr) {
if b.trackSchemaDeps {
if texpr.ResolvedType().UserDefined() {
if texpr != nil && texpr.ResolvedType().UserDefined() {
typedesc.GetTypeDescriptorClosure(texpr.ResolvedType()).ForEach(func(id descpb.ID) {
b.schemaTypeDeps.Add(int(id))
})
Expand Down

0 comments on commit d4c3db5

Please sign in to comment.