From 6741f261f8880eae2587725fe0b3ae85d95e7b5a Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 5 Apr 2021 13:50:12 -0400 Subject: [PATCH] sql: wrap CastExpr within IndirectionExpr in a ParenExpr Fixes https://github.com/cockroachdb/cockroach/issues/63097. When we type check ParenExpr, we remove the parentheses. This can cause issues for IndirectionExprs. For example, something like `('{a}'::_typ)[1]` would turn into `'{a}'::_typ[1]` after type checking, resulting in the `[1]` being interpreted as part of the type. This would result in errors when trying to use these expressions in default expressions. This patch checks for this specific case, and if it finds that there is a CastExpr within an IndirecionExpr, it will wrap it in a ParenExpr. Release note: None --- pkg/sql/logictest/testdata/logic_test/enums | 39 +++++++++++++++++++++ pkg/sql/sem/tree/expr.go | 10 +++++- pkg/sql/sem/tree/type_check_test.go | 3 ++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/pkg/sql/logictest/testdata/logic_test/enums b/pkg/sql/logictest/testdata/logic_test/enums index 5f3346181f40..62b097e6a287 100644 --- a/pkg/sql/logictest/testdata/logic_test/enums +++ b/pkg/sql/logictest/testdata/logic_test/enums @@ -1179,3 +1179,42 @@ query T SELECT _enum FROM t58889 WHERE _enum::greeting58889 IN (NULL, 'hi':::greeting58889); ---- hi + + +subtest enum_array_cast + +statement ok +CREATE TYPE typ AS ENUM('a', 'b', 'c') + +statement ok +CREATE TABLE arr_t (i STRING DEFAULT ('{a}'::_typ)[1]::STRING) + +statement ok +INSERT INTO arr_t VALUES (default) + +query T +SELECT * FROM arr_t +---- +a + +statement ok +CREATE TABLE arr_t2 (i typ DEFAULT ('{a, b, c}'::typ[])[2]) + +statement ok +INSERT INTO arr_t2 VALUES (default) + +query T +SELECT * FROM arr_t2 +---- +b + +statement ok +CREATE TABLE arr_t3 (i STRING DEFAULT ('{c}'::_typ:::_typ)[1]::STRING) + +statement ok +INSERT INTO arr_t3 VALUES (default) + +query T +SELECT * FROM arr_t3 +---- +c diff --git a/pkg/sql/sem/tree/expr.go b/pkg/sql/sem/tree/expr.go index 0c3b0fb35ba6..30cb83da35cb 100644 --- a/pkg/sql/sem/tree/expr.go +++ b/pkg/sql/sem/tree/expr.go @@ -1624,7 +1624,15 @@ type IndirectionExpr struct { // Format implements the NodeFormatter interface. func (node *IndirectionExpr) Format(ctx *FmtCtx) { - exprFmtWithParen(ctx, node.Expr) + // If the subExpr is a CastExpr, we need to wrap it in a ParenExpr, + // otherwise the indirection will get interpreted as part of the type. + // Ex. ('{a}'::_typ)[1] vs. '{a}'::_typ[1]. + if _, isCast := node.Expr.(*CastExpr); isCast { + withParens := ParenExpr{Expr: node.Expr} + exprFmtWithParen(ctx, &withParens) + } else { + exprFmtWithParen(ctx, node.Expr) + } ctx.FormatNode(&node.Indirection) } diff --git a/pkg/sql/sem/tree/type_check_test.go b/pkg/sql/sem/tree/type_check_test.go index 1d6c7290e634..862d72d1606b 100644 --- a/pkg/sql/sem/tree/type_check_test.go +++ b/pkg/sql/sem/tree/type_check_test.go @@ -196,6 +196,9 @@ func TestTypeCheck(t *testing.T) { {`1:::d.s.t3 + 1.4`, `1:::DECIMAL + 1.4:::DECIMAL`}, {`1 IS OF (d.t1, t2)`, `1:::INT8 IS OF (INT8, STRING)`}, {`1::d.t1`, `1:::INT8`}, + + {`(('{' || 'a' ||'}')::STRING[])[1]::STRING`, `((('{':::STRING || 'a':::STRING) || '}':::STRING)::STRING[])[1:::INT8]`}, + {`(('{' || '1' ||'}')::INT[])[1]`, `((('{':::STRING || '1':::STRING) || '}':::STRING)::INT8[])[1:::INT8]`}, } ctx := context.Background() for _, d := range testData {