Skip to content

Commit

Permalink
sql: wrap CastExpr within IndirectionExpr in a ParenExpr
Browse files Browse the repository at this point in the history
Fixes cockroachdb#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
  • Loading branch information
the-ericwang35 committed Apr 13, 2021
1 parent dbc9c4b commit 6741f26
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 1 deletion.
39 changes: 39 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/enums
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 9 additions & 1 deletion pkg/sql/sem/tree/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/sql/sem/tree/type_check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 6741f26

Please sign in to comment.