Skip to content

Commit

Permalink
sql: add tests for tail-call property
Browse files Browse the repository at this point in the history
This commit adds tests for the `ExtractTailCalls` function from the
previous commit, and adds a `tail-call` field to `UDFCall` expressions
that are in tail-call position in another routine. It also adds a
regression test for cockroachdb#120916.

Informs cockroachdb#120916

Release note: None
  • Loading branch information
DrewKimball committed Mar 28, 2024
1 parent d12fe78 commit 15a74f4
Show file tree
Hide file tree
Showing 22 changed files with 1,411 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ call
├── fd: ()-->(5)
└── tuple [type=tuple{void}]
└── udf: _stmt_raise_1 [type=void]
├── tail-call
├── args
│ └── variable: x:1 [type=int]
├── params: x:2(int)
Expand Down
27 changes: 27 additions & 0 deletions pkg/ccl/logictestccl/testdata/logic_test/nested_routines
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# LogicTest: !local-mixed-23.1 !local-mixed-23.2

# Regression test for #120916 - the nested routine is not in tail-call position,
# and so cannot be a target for TCO.
statement ok
CREATE FUNCTION f_nested(x INT) RETURNS INT AS $$
BEGIN
x := x * 2;
RETURN x;
END
$$ LANGUAGE PLpgSQL;

statement ok
CREATE FUNCTION f() RETURNS RECORD AS $$
DECLARE
a INT := -2;
BEGIN
a := f_nested(a);
RAISE NOTICE 'here';
RETURN (a, -a);
END
$$ LANGUAGE PLpgSQL;

query II
SELECT * FROM f() AS g(x INT, y INT);
----
-4 4
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 = 26,
shard_count = 27,
tags = [
"ccl_test",
"cpu:2",
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 = 26,
shard_count = 27,
tags = [
"ccl_test",
"cpu:2",
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 = 27,
shard_count = 28,
tags = [
"ccl_test",
"cpu:2",
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 = 26,
shard_count = 27,
tags = [
"ccl_test",
"cpu:1",
Expand Down

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 = 33,
shard_count = 34,
tags = [
"ccl_test",
"cpu:1",
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 = 26,
shard_count = 27,
tags = [
"ccl_test",
"cpu:1",
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 = 42,
shard_count = 43,
tags = [
"ccl_test",
"cpu:1",
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.

21 changes: 17 additions & 4 deletions pkg/sql/opt/memo/expr_format.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ type ExprFmtCtx struct {
// seenUDFs is used to ensure that formatting of recursive UDFs does not
// infinitely recurse.
seenUDFs map[*UDFDefinition]struct{}

// tailCalls allows for quick lookup of all the routines in tail-call position
// when the last body statement of a routine is formatted.
tailCalls map[*UDFCallExpr]struct{}
}

// makeExprFmtCtxForString creates an expression formatting context from a new
Expand Down Expand Up @@ -957,13 +961,18 @@ func (f *ExprFmtCtx) formatScalarWithLabel(
}
n := tp.Child("body")
for i := range def.Body {
stmtNode := n
if i == 0 && def.CursorDeclaration != nil {
// The first statement is opening a cursor.
cur := n.Child("open-cursor")
f.formatExpr(def.Body[i], cur)
continue
stmtNode = n.Child("open-cursor")
}
prevTailCalls := f.tailCalls
if i == len(def.Body)-1 {
f.tailCalls = make(map[*UDFCallExpr]struct{})
ExtractTailCalls(def.Body[i], f.tailCalls)
}
f.formatExpr(def.Body[i], n)
f.formatExpr(def.Body[i], stmtNode)
f.tailCalls = prevTailCalls
}
delete(f.seenUDFs, def)
} else {
Expand Down Expand Up @@ -998,6 +1007,10 @@ func (f *ExprFmtCtx) formatScalarWithLabel(
if !udf.Def.CalledOnNullInput {
tp.Child("strict")
}
if _, tailCall := f.tailCalls[udf]; tailCall {
// This routine is in tail-call position in the parent routine.
tp.Child("tail-call")
}
formatRoutineArgs(udf.Args, tp)
formatUDFDefinition(udf.Def, tp)
}
Expand Down
Loading

0 comments on commit 15a74f4

Please sign in to comment.