From 2778c5c9c5e3d15fc9ccfab67cf8bdc6e91b8702 Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Mon, 8 Mar 2021 13:18:16 -0500 Subject: [PATCH] opt: detect invalid tuple comparison with ANY Fixes #61229. Release justification: backportable bug fix. Release note (bug fix): fixed a case where an invalid tuple comparison using ANY was causing an internal error; we now return "unsupported comparison operator". --- pkg/sql/opt/optbuilder/testdata/subquery | 21 +++++++++++++++++++++ pkg/sql/sem/tree/type_check.go | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/pkg/sql/opt/optbuilder/testdata/subquery b/pkg/sql/opt/optbuilder/testdata/subquery index 41c3885b60ac..efa481d53a57 100644 --- a/pkg/sql/opt/optbuilder/testdata/subquery +++ b/pkg/sql/opt/optbuilder/testdata/subquery @@ -2255,3 +2255,24 @@ build SELECT 1 FROM (VALUES (1)) AS a(x) HAVING (SELECT true FROM (VALUES (a.x)) AS b(y)) ---- error (42803): subquery uses ungrouped column "x" from outer query + +build +SELECT ((1, 2), (3, 4)) = ANY (VALUES (('foo', 'bar'))) +---- +error (22023): unsupported comparison operator: = ANY + +# Regression test for #61229 - detect uncomparable tuple types. +build +SELECT (1, 1) = ANY (VALUES ('foo', 'bar')) +---- +error (22023): unsupported comparison operator: = ANY + +build +SELECT ARRAY[1, 2] = ANY (VALUES (ARRAY['foo', 'bar'])) +---- +error (22023): unsupported comparison operator: = ANY + +build +SELECT (1, 1) = ANY (VALUES (1, 2, 3)) +---- +error (22023): unsupported comparison operator: = ANY diff --git a/pkg/sql/sem/tree/type_check.go b/pkg/sql/sem/tree/type_check.go index 930941a515c4..ac5d0da9b4d8 100644 --- a/pkg/sql/sem/tree/type_check.go +++ b/pkg/sql/sem/tree/type_check.go @@ -1852,12 +1852,33 @@ func typeCheckComparisonOpWithSubOperator( } } fn, ok := ops.LookupImpl(cmpTypeLeft, cmpTypeRight) - if !ok { + if !ok || !deepCheckValidCmpOp(ops, cmpTypeLeft, cmpTypeRight) { return nil, nil, nil, false, subOpCompError(cmpTypeLeft, rightTyped.ResolvedType(), subOp, op) } return leftTyped, rightTyped, fn, false, nil } +// deepCheckValidCmpOp performs extra checks that a given operation is valid +// when the types are tuples. +func deepCheckValidCmpOp(ops cmpOpOverload, leftType, rightType *types.T) bool { + if leftType.Family() == types.TupleFamily && rightType.Family() == types.TupleFamily { + l := leftType.TupleContents() + r := rightType.TupleContents() + if len(l) != len(r) { + return false + } + for i := range l { + if _, ok := ops.LookupImpl(l[i], r[i]); !ok { + return false + } + if !deepCheckValidCmpOp(ops, l[i], r[i]) { + return false + } + } + } + return true +} + func subOpCompError(leftType, rightType *types.T, subOp, op ComparisonOperator) error { sig := fmt.Sprintf(compSignatureWithSubOpFmt, leftType, subOp, op, rightType) return pgerror.Newf(pgcode.InvalidParameterValue, unsupportedCompErrFmt, sig)