Skip to content

Commit

Permalink
sql: return expected user-facing error for invalid unnest arguments
Browse files Browse the repository at this point in the history
Previously, the `unnest` builtin function could trigger an internal
error when passed multiple non array-type arguments. This is because
it only checked whether the arguments were `NULL` when determining
whether they were of a valid type. This is not a problem for some types,
like `INT`, because they will prevent the function overloads from being
resolved.

However, since `TEXT` arguments can be cast to `ARRAY` types, function
overload resolution succeeds. Since `unnest` only checked for `NULL`,
it would assume that the arguments were array types, and attempt to
retrieve the (nil) array contents. For the single-argument case this
wasn't a problem because nil is used to signal invalid arguments, anyway.
However, the multiple-argument case wraps the array contents of each argument
type into a tuple, resulting in a tuple-type of nil types. This caused
a nil-pointer dereference later down the line.

This patch prevents the internal error by checking directly that the arguments
are `ARRAY` types, to ensure that the array contents are non-nil. If the
check fails, the (nil) `tree.UnknownReturnType` type is returned, which
signals an invalid type. That results in an expected, user-facing error instead
of an internal error.

The `information_schema._pg_expandarray` builtin function had a similar
vulnerability. This patch fixes that as well.

Fixes #110952

Release note (bug fix): Fixed an edge case in the `unnest` and
`information_schema._pg_expandarray` builtin functions that could cause
an internal error when passed string arguments that could be cast to
an array.
  • Loading branch information
DrewKimball committed Sep 20, 2023
1 parent 0ff99f1 commit 806f559
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
24 changes: 24 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/srfs
Original file line number Diff line number Diff line change
Expand Up @@ -1406,3 +1406,27 @@ NULL
NULL
4
5

# Regression test for #110952 - providing invalid arguments to unnest should
# not trigger an internal error.
statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(string\)
SELECT unnest('{}');

statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(string, string, string\)
SELECT unnest('{}', '{}', '{}');

statement error pgcode 42883 pq: unknown signature: unnest\(int\)
SELECT unnest(1);

statement error pgcode 42883 pq: unknown signature: unnest\(int, int, int\)
SELECT unnest(1, 2, 3);

statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(unknown\)
SELECT unnest(NULL);

statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(unknown, unknown, unknown\)
SELECT unnest(NULL, NULL, NULL);

# pg_expandarray handles return types similarly to unnest.
statement error pgcode 42804 pq: could not determine polymorphic type: information_schema._pg_expandarray\(string\)
SELECT information_schema._pg_expandarray('{}');
6 changes: 3 additions & 3 deletions pkg/sql/sem/builtins/generator_builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ var generators = map[string]builtinDefinition{
makeGeneratorOverloadWithReturnType(
tree.ParamTypes{{Name: "input", Typ: types.AnyArray}},
func(args []tree.TypedExpr) *types.T {
if len(args) == 0 || args[0].ResolvedType().Family() == types.UnknownFamily {
if len(args) == 0 || args[0].ResolvedType().Family() != types.ArrayFamily {
return tree.UnknownReturnType
}
return args[0].ResolvedType().ArrayContents()
Expand All @@ -317,7 +317,7 @@ var generators = map[string]builtinDefinition{
returnTypes := make([]*types.T, len(args))
labels := make([]string, len(args))
for i, arg := range args {
if arg.ResolvedType().Family() == types.UnknownFamily {
if arg.ResolvedType().Family() != types.ArrayFamily {
return tree.UnknownReturnType
}
returnTypes[i] = arg.ResolvedType().ArrayContents()
Expand All @@ -335,7 +335,7 @@ var generators = map[string]builtinDefinition{
makeGeneratorOverloadWithReturnType(
tree.ParamTypes{{Name: "input", Typ: types.AnyArray}},
func(args []tree.TypedExpr) *types.T {
if len(args) == 0 || args[0].ResolvedType().Family() == types.UnknownFamily {
if len(args) == 0 || args[0].ResolvedType().Family() != types.ArrayFamily {
return tree.UnknownReturnType
}
t := args[0].ResolvedType().ArrayContents()
Expand Down

0 comments on commit 806f559

Please sign in to comment.