Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
126479: sql: add TRIGGER datatype r=DrewKimball a=DrewKimball

This patch adds support for the special datatype `TRIGGER`. It is only used as the return type of a trigger function, and leads to an error in other contexts. This patch does not add support for trigger functions, tracked in cockroachdb#126356.

Fixes cockroachdb#126476

Release note: None

Co-authored-by: Drew Kimball <[email protected]>
  • Loading branch information
craig[bot] and DrewKimball committed Jul 20, 2024
2 parents a745d74 + a8cdedd commit b341a88
Show file tree
Hide file tree
Showing 37 changed files with 407 additions and 27 deletions.
164 changes: 164 additions & 0 deletions pkg/ccl/logictestccl/testdata/logic_test/triggers
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# TODO(#126356): remove this case when trigger functions are supported.
statement error pgcode 0A000 pq: unimplemented: trigger functions are not yet supported
CREATE FUNCTION f() RETURNS TRIGGER LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

# ==============================================================================
# Trigger functions cannot be directly invoked.
# ==============================================================================

subtest direct_invocation

# TODO(#126356): uncomment these cases when trigger functions are supported.
#statement ok
#CREATE FUNCTION f() RETURNS TRIGGER LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;
#
#statement error pgcode 0A000 pq: trigger functions can only be called as triggers
#SELECT f();
#
#statement error pgcode 0A000 pq: trigger functions can only be called as triggers
#CREATE FUNCTION foo() RETURNS INT LANGUAGE SQL AS $$ SELECT f(); SELECT 1; $$;
#
#statement error pgcode 0A000 pq: trigger functions can only be called as triggers
#CREATE FUNCTION foo() RETURNS INT LANGUAGE PLpgSQL AS $$ BEGIN SELECT f(); RETURN 1; END $$;
#
#statement ok
#DROP FUNCTION f;

# ==============================================================================
# Test invalid usage of parameters in trigger functions.
# ==============================================================================

# Trigger functions are not allowed to be defined with parameters. Instead,
# arguments are passed through the implicitly defined TG_ARGV variable.
subtest parameters

statement error pgcode 42P13 pq: trigger functions cannot have declared arguments
CREATE FUNCTION f(x TEXT) RETURNS TRIGGER LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

statement error pgcode 42P13 pq: function result type must be string because of OUT parameters
CREATE FUNCTION f(OUT x TEXT) RETURNS TRIGGER LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

statement error pgcode 42P13 pq: function result type must be string because of OUT parameters
CREATE FUNCTION f(INOUT x TEXT) RETURNS TRIGGER LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

# ==============================================================================
# Test invalid usage of the TRIGGER datatype in PL/pgSQL routines.
# ==============================================================================

subtest trigger_in_plpgsql_routine

statement error pgcode 0A000 pq: cannot accept a value of type trigger
CREATE FUNCTION f() RETURNS RECORD LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL::TRIGGER; END $$;

statement error pgcode 0A000 pq: PL/pgSQL functions cannot accept type trigger
CREATE FUNCTION f(x TRIGGER) RETURNS INT LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

statement error pgcode 0A000 pq: PL/pgSQL functions cannot accept type trigger
CREATE FUNCTION f(OUT x TRIGGER) LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

statement error pgcode 0A000 pq: PL/pgSQL functions cannot accept type trigger
CREATE FUNCTION f(INOUT x TRIGGER) RETURNS INT LANGUAGE PLpgSQL AS $$ BEGIN RETURN NULL; END $$;

statement error pgcode 0A000 pq: PL/pgSQL functions cannot accept type trigger
CREATE PROCEDURE p(x TRIGGER) LANGUAGE PLpgSQL AS $$ BEGIN END $$;

statement error pgcode 0A000 pq: PL/pgSQL functions cannot accept type trigger
CREATE PROCEDURE p(OUT x TRIGGER) LANGUAGE PLpgSQL AS $$ BEGIN END $$;

statement error pgcode 0A000 pq: PL/pgSQL functions cannot accept type trigger
CREATE PROCEDURE p(INOUT x TRIGGER) LANGUAGE PLpgSQL AS $$ BEGIN END $$;

# ==============================================================================
# Test invalid usage of the TRIGGER datatype in SQL routines.
# ==============================================================================

subtest trigger_in_sql_routine

statement error pgcode 0A000 pq: cannot accept a value of type trigger
CREATE FUNCTION f() RETURNS RECORD LANGUAGE SQL AS $$ SELECT NULL::TRIGGER; $$;

statement error pgcode 42P13 pq: SQL functions cannot return type trigger
CREATE FUNCTION f() RETURNS TRIGGER LANGUAGE SQL AS $$ SELECT NULL $$;

statement error pgcode 42P13 pq: SQL functions cannot have arguments of type trigger
CREATE FUNCTION f(x TRIGGER) RETURNS INT LANGUAGE SQL AS $$ SELECT NULL $$;

statement error pgcode 42P13 pq: SQL functions cannot return type trigger
CREATE FUNCTION f(OUT x TRIGGER) LANGUAGE SQL AS $$ SELECT NULL $$;

statement error pgcode 42P13 pq: SQL functions cannot return type trigger
CREATE FUNCTION f(INOUT x TRIGGER) RETURNS INT LANGUAGE SQL AS $$ SELECT NULL $$;

statement error pgcode 42P13 pq: SQL functions cannot have arguments of type trigger
CREATE PROCEDURE p(x TRIGGER) LANGUAGE SQL AS $$ SELECT NULL $$;

statement error pgcode 42P13 pq: SQL functions cannot return type trigger
CREATE PROCEDURE p(OUT x TRIGGER) LANGUAGE SQL AS $$ SELECT NULL $$;

statement error pgcode 42P13 pq: SQL functions cannot return type trigger
CREATE PROCEDURE p(INOUT x TRIGGER) LANGUAGE SQL AS $$ SELECT NULL $$;

# ==============================================================================
# Test invalid usage of the TRIGGER datatype in SQL statements.
# ==============================================================================

subtest trigger_in_sql_statement

# Cast.
statement error pgcode 0A000 pq: cannot accept a value of type trigger
SELECT NULL::TRIGGER;

# Trigger array cast.
statement error pgcode 42704 pq: at or near "EOF": syntax error: type trigger\[\] does not exist
SELECT NULL::TRIGGER[];

# Invalid cast from integer.
statement error pgcode 42846 pq: invalid cast: int -> trigger
SELECT 1::TRIGGER;

# Type annotation.
statement error pgcode 0A000 pq: cannot accept a value of type trigger
SELECT NULL:::TRIGGER;

# Builtin type conversion function.
statement error pgcode 0A000 pq: cannot accept a value of type trigger
SELECT triggerin(1);

# Builtin type conversion function with NULL argument.
# NOTE: this case succeeds because the function is not actually called
# or fully type-checked when it is supplied NULL arguments.
# statement error pgcode 0A000 pq: cannot accept a value of type trigger
statement ok
SELECT triggerin(NULL);

# ==============================================================================
# Test invalid usage of the TRIGGER datatype in CREATE statements.
# ==============================================================================

subtest trigger_in_create

# Column type.
statement error pgcode 42P16 pq: value type trigger cannot be used for table columns
CREATE TABLE t (x INT, y TRIGGER, z TEXT);

# Array column type.
statement error pgcode 42704 pq: at or near ",": syntax error: type trigger\[\] does not exist
CREATE TABLE t (x INT, y TRIGGER[], z TEXT);

# Cast in partial index predicate.
statement error pgcode 0A000 pq: cannot accept a value of type trigger
CREATE TABLE t (x INT, y INT, INDEX (y) WHERE (NULL::TRIGGER IS NOT NULL));

# Cast in computed column expression.
statement error pgcode 0A000 pq: cannot accept a value of type trigger
CREATE TABLE t (x INT, y BOOL GENERATED ALWAYS AS (NULL::TRIGGER IS NOT NULL) STORED);

# Trigger UDT field.
statement error pgcode 0A000 pq: cannot accept a value of type trigger
CREATE TYPE udt AS (x INT, y TRIGGER, z TEXT);

# Trigger array UDT field.
statement error pgcode 42601 pq: at or near "\[": syntax error
CREATE TYPE udt AS (x INT, y TRIGGER[], z TEXT);

subtest end
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ go_test(
"//build/toolchains:is_heavy": {"test.Pool": "heavy"},
"//conditions:default": {"test.Pool": "large"},
}),
shard_count = 29,
shard_count = 30,
tags = ["cpu:2"],
deps = [
"//pkg/base",
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/fakedist-disk/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ go_test(
"//build/toolchains:is_heavy": {"test.Pool": "heavy"},
"//conditions:default": {"test.Pool": "large"},
}),
shard_count = 29,
shard_count = 30,
tags = ["cpu:2"],
deps = [
"//pkg/base",
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/fakedist-vec-off/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ go_test(
"//build/toolchains:is_heavy": {"test.Pool": "heavy"},
"//conditions:default": {"test.Pool": "large"},
}),
shard_count = 30,
shard_count = 31,
tags = ["cpu:2"],
deps = [
"//pkg/base",
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/fakedist/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
"//pkg/ccl/logictestccl:testdata", # keep
],
exec_properties = {"test.Pool": "large"},
shard_count = 29,
shard_count = 30,
tags = ["cpu:1"],
deps = [
"//pkg/base",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/tests/local-mixed-23.2/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
"//pkg/ccl/logictestccl:testdata", # keep
],
exec_properties = {"test.Pool": "large"},
shard_count = 25,
shard_count = 26,
tags = ["cpu:1"],
deps = [
"//pkg/base",
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/local-mixed-23.2/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ go_test(
"//pkg/sql/opt/exec/execbuilder:testdata", # keep
],
exec_properties = {"test.Pool": "large"},
shard_count = 36,
shard_count = 37,
tags = ["cpu:1"],
deps = [
"//pkg/base",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
"//pkg/ccl/logictestccl:testdata", # keep
],
exec_properties = {"test.Pool": "large"},
shard_count = 29,
shard_count = 30,
tags = ["cpu:1"],
deps = [
"//pkg/base",
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/local-vec-off/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/tests/local/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
"//pkg/ccl/logictestccl:testdata", # keep
],
exec_properties = {"test.Pool": "large"},
shard_count = 46,
shard_count = 47,
tags = ["cpu:1"],
deps = [
"//pkg/base",
Expand Down
7 changes: 7 additions & 0 deletions pkg/ccl/logictestccl/tests/local/generated_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions pkg/sql/create_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,10 @@ func createCompositeTypeDesc(
if err != nil {
return nil, err
}
err = tree.CheckUnsupportedType(params.ctx, &params.p.semaCtx, typ)
if err != nil {
if typ.Identical(types.Trigger) {
return nil, tree.CannotAcceptTriggerErr
}
if err = tree.CheckUnsupportedType(params.ctx, &params.p.semaCtx, typ); err != nil {
return nil, err
}
if typ.UserDefined() {
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/exec_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2070,6 +2070,10 @@ func checkResultType(typ *types.T, fmtCode pgwirebase.FormatCode) error {
case types.AnyFamily:
// Placeholder case.
return errors.Errorf("could not determine data type of %s", typ)
case types.TriggerFamily:
// The TRIGGER datatype is only allowed as the return type of a trigger
// function.
return tree.CannotAcceptTriggerErr
default:
return errors.Errorf("unsupported result type: %s", typ)
}
Expand Down
Loading

0 comments on commit b341a88

Please sign in to comment.