Skip to content

Commit

Permalink
sql: fix serialization of datums and prefix casts
Browse files Browse the repository at this point in the history
This change addresses a few related problems (described in more detail
in cockroachdb#12532):
 - ambiguous datum types after serialization
 - invalid prefix casts after expression processing (like `INTERVAL INTERVAL `1.5s`').

Changes:

 - a new FmtFlag adds type annotations to datums and placeholders. This ensures
   that expressions that contain `DDInterval`, `DDate` can be formatted and
   re-parsed correctly. This replaces ad-hoc type prepending like
   `INTERVAL '..'` or `DATE '..'`.

 - `CastExpr.TypeCheck` now returns the underlying type-checked expression
   directly when it is a Datum that we know for sore is of identical type.

 - `castPrefix` (renamed to `castPrepend`) now only functions if the
   underlying expression is a string literal (preventing incorrect expressions
   like `DECIMAL '1.0':::string`). `castPrefixParens` is removed (it
   was incorrect).

 - `AnnotateTypeExpr.TypeCheck` now returns the underlying type-checked
   expression rather than changing the `AnnotateTypeExpr` in-place and
   returning it (which could result in double annotations with the new
   `FmtFlag`). `AnnotateTypeExpr` is no longer a `TypedExpr` so it is never part
   of a type-checked expression (which makes sense).

 - type checking tests are extended to verify the serliazed type-checked
   expression, which verifies both serialization and type resolution.

Note that changing the prepend syntax to a `AnnotateTypeExpr` was considered
but that doesn't work for things like `DECIMAL '2.0'`.

Fixes cockroachdb#12532. Resolves some of the concerns in cockroachdb#12611.
  • Loading branch information
RaduBerinde committed Jan 13, 2017
1 parent 62f24f8 commit 5f87a27
Show file tree
Hide file tree
Showing 17 changed files with 271 additions and 202 deletions.
2 changes: 1 addition & 1 deletion pkg/sql/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ func applyColumnMutation(
); err != nil {
return err
}
s := t.Default.String()
s := parser.Serialize(t.Default)
col.DefaultExpr = &s
}

Expand Down
28 changes: 16 additions & 12 deletions pkg/sql/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,17 +383,21 @@ func (p *planner) CreateView(n *parser.CreateView) (planNode, error) {

var queryBuf bytes.Buffer
var fmtErr error
n.AsSource.Format(&queryBuf, parser.FmtNormalizeTableNames(
parser.FmtSimple,
func(t *parser.NormalizableTableName) *parser.TableName {
tn, err := p.QualifyWithDatabase(t)
if err != nil {
log.Warningf(p.ctx(), "failed to qualify table name %q with database name: %v", t, err)
fmtErr = err
return nil
}
return tn
}))
n.AsSource.Format(
&queryBuf,
parser.FmtNormalizeTableNames(
parser.FmtParsable,
func(t *parser.NormalizableTableName) *parser.TableName {
tn, err := p.QualifyWithDatabase(t)
if err != nil {
log.Warningf(p.ctx(), "failed to qualify table name %q with database name: %v", t, err)
fmtErr = err
return nil
}
return tn
},
),
)
if fmtErr != nil {
return nil, fmtErr
}
Expand Down Expand Up @@ -1471,7 +1475,7 @@ func makeCheckConstraint(
inuseNames[name] = struct{}{}
}
}
return &sqlbase.TableDescriptor_CheckConstraint{Expr: d.Expr.String(), Name: name}, nil
return &sqlbase.TableDescriptor_CheckConstraint{Expr: parser.Serialize(d.Expr), Name: name}, nil
}

// CreateTestTableDescriptor converts a SQL string to a table for test purposes.
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/distsql_physical_planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ func mergePlans(
// exprFmtFlagsBase are FmtFlags used for serializing expressions; a proper
// IndexedVar formatting function needs to be added on.
var exprFmtFlagsBase = parser.FmtStarDatumFormat(
parser.FmtSimple,
parser.FmtParsable,
func(buf *bytes.Buffer, _ parser.FmtFlags) {
fmt.Fprintf(buf, "0")
},
Expand Down
10 changes: 7 additions & 3 deletions pkg/sql/parser/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1321,11 +1321,15 @@ func (d *DInterval) ValueAsString() string {
return (time.Duration(d.Duration.Nanos) * time.Nanosecond).String()
}

// Format implements the NodeFormatter interface. Example: "INTERVAL `1h2m`".
// Format implements the NodeFormatter interface.
func (d *DInterval) Format(buf *bytes.Buffer, f FmtFlags) {
buf.WriteString("INTERVAL '")
if !f.bareStrings {
buf.WriteByte('\'')
}
buf.WriteString(d.ValueAsString())
buf.WriteByte('\'')
if !f.bareStrings {
buf.WriteByte('\'')
}
}

// Size implements the Datum interface.
Expand Down
12 changes: 6 additions & 6 deletions pkg/sql/parser/datum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ func TestDatumOrdering(t *testing.T) {

// Intervals
{`'1 day':::interval`, noPrev, noNext,
`INTERVAL '-9223372036854775808m-9223372036854775808d-2562047h47m16.854775808s'`,
`INTERVAL '9223372036854775807m9223372036854775807d2562047h47m16.854775807s'`},
`'-9223372036854775808m-9223372036854775808d-2562047h47m16.854775808s'`,
`'9223372036854775807m9223372036854775807d2562047h47m16.854775807s'`},
// Max interval: we use Postgres syntax, because Go doesn't accept
// months/days and ISO8601 doesn't accept nanoseconds.
{`'9223372036854775807 months 9223372036854775807 days ` +
`2562047 hours 47 minutes 16 seconds 854775807 nanoseconds':::interval`,
noPrev, valIsMax,
`INTERVAL '-9223372036854775808m-9223372036854775808d-2562047h47m16.854775808s'`,
`INTERVAL '9223372036854775807m9223372036854775807d2562047h47m16.854775807s'`},
`'-9223372036854775808m-9223372036854775808d-2562047h47m16.854775808s'`,
`'9223372036854775807m9223372036854775807d2562047h47m16.854775807s'`},
// It's hard to generate a minimum interval! We can't use a
// negative value inside the string constant, because that's not
// allowed in a Postgres duration specification. We can't use the
Expand All @@ -113,8 +113,8 @@ func TestDatumOrdering(t *testing.T) {
`2562047 hours 47 minutes 16 seconds':::interval` +
`-'1 month 1 day 854775808 nanoseconds':::interval`,
valIsMin, noNext,
`INTERVAL '-9223372036854775808m-9223372036854775808d-2562047h47m16.854775808s'`,
`INTERVAL '9223372036854775807m9223372036854775807d2562047h47m16.854775807s'`},
`'-9223372036854775808m-9223372036854775808d-2562047h47m16.854775808s'`,
`'9223372036854775807m9223372036854775807d2562047h47m16.854775807s'`},

// NULL
{`NULL`, valIsMin, valIsMax, `NULL`, `NULL`},
Expand Down
5 changes: 0 additions & 5 deletions pkg/sql/parser/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2248,11 +2248,6 @@ func (expr *IndirectionExpr) Eval(ctx *EvalContext) (Datum, error) {
return arr.Array[subscriptIdx-1], nil
}

// Eval implements the TypedExpr interface.
func (expr *AnnotateTypeExpr) Eval(ctx *EvalContext) (Datum, error) {
return expr.Expr.(TypedExpr).Eval(ctx)
}

// Eval implements the TypedExpr interface.
func (expr *CollateExpr) Eval(ctx *EvalContext) (Datum, error) {
d, err := expr.Expr.(TypedExpr).Eval(ctx)
Expand Down
168 changes: 84 additions & 84 deletions pkg/sql/parser/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,13 +544,13 @@ func TestEval(t *testing.T) {
{`'2010-09-28 12:00:00.1-04'::timestamp`, `'2010-09-28 16:00:00.1+00:00'`},
{`'2010-09-28 12:00:00.1-04'::timestamp::text`, `'2010-09-28 16:00:00.1+00:00'`},
{`'2010-09-28 12:00:00.1-04'::timestamptz::text`, `'2010-09-28 16:00:00.1+00:00'`},
{`'12h2m1s23ms'::interval`, `INTERVAL '12h2m1.023s'`},
{`'12h2m1s23ms'::interval`, `'12h2m1.023s'`},
{`'12h2m1s23ms'::interval::text`, `'12h2m1.023s'`},
{`interval '1'`, `INTERVAL '1s'`},
{`CAST('1' AS interval)`, `INTERVAL '1s'`},
{`'1'::interval`, `INTERVAL '1s'`},
{`1::interval`, `INTERVAL '1µs'`},
{`(1::interval)::interval`, `INTERVAL '1µs'`},
{`interval '1'`, `'1s'`},
{`CAST('1' AS interval)`, `'1s'`},
{`'1'::interval`, `'1s'`},
{`1::interval`, `'1µs'`},
{`(1::interval)::interval`, `'1µs'`},
{`'2010-09-28'::date + 3`, `'2010-10-01'`},
{`3 + '2010-09-28'::date`, `'2010-10-01'`},
{`'2010-09-28'::date - 3`, `'2010-09-25'`},
Expand All @@ -564,7 +564,7 @@ func TestEval(t *testing.T) {
{`'2010-09-28 12:00:00.1-04:00'::timestamp - '12 hours 2 minutes'::interval`, `'2010-09-28 03:58:00.1+00:00'`},
{`'2010-09-28 12:00:00.1-04:00'::timestamp - 'PT12H2M'::interval`, `'2010-09-28 03:58:00.1+00:00'`},
{`'2010-09-28 12:00:00.1-04:00'::timestamp - '12:2'::interval`, `'2010-09-28 03:58:00.1+00:00'`},
{`'2010-09-28 12:00:00.1-04:00'::timestamp - '2010-09-28 12:00:00.1+00:00'::timestamp`, `INTERVAL '4h0m0s'`},
{`'2010-09-28 12:00:00.1-04:00'::timestamp - '2010-09-28 12:00:00.1+00:00'::timestamp`, `'4h0m0s'`},
{`'1970-01-01 00:01:00.123456-00:00'::timestamp::int`, `60`},
{`'1970-01-01 00:01:00.123456-00:00'::timestamptz::int`, `60`},
{`'1970-01-10'::date::int`, `9`},
Expand All @@ -580,15 +580,15 @@ func TestEval(t *testing.T) {
{`10::int::date`, `'1970-01-11'`},
{`10::int::timestamp`, `'1970-01-01 00:00:10+00:00'`},
{`10::int::timestamptz`, `'1970-01-01 00:00:10+00:00'`},
{`10123456::int::interval`, `INTERVAL '10.123456s'`},
{`10123456::int::interval`, `'10.123456s'`},
// Type annotation expressions.
{`ANNOTATE_TYPE('s', string)`, `'s'`},
{`ANNOTATE_TYPE('s', bytes)`, `b's'`},
{`ANNOTATE_TYPE('2010-09-28', date)`, `'2010-09-28'`},
{`ANNOTATE_TYPE('PT12H2M', interval)`, `INTERVAL '12h2m0s'`},
{`ANNOTATE_TYPE('2 02:12', interval)`, `INTERVAL '0m2d2h12m0s'`},
{`ANNOTATE_TYPE('2 02:12:34', interval)`, `INTERVAL '0m2d2h12m34s'`},
{`ANNOTATE_TYPE('1-2 02:12', interval)`, `INTERVAL '14m0d2h12m0s'`},
{`ANNOTATE_TYPE('PT12H2M', interval)`, `'12h2m0s'`},
{`ANNOTATE_TYPE('2 02:12', interval)`, `'0m2d2h12m0s'`},
{`ANNOTATE_TYPE('2 02:12:34', interval)`, `'0m2d2h12m34s'`},
{`ANNOTATE_TYPE('1-2 02:12', interval)`, `'14m0d2h12m0s'`},
{`ANNOTATE_TYPE('2010-09-28', timestamp)`, `'2010-09-28 00:00:00+00:00'`},
{`ANNOTATE_TYPE('2010-09-28', timestamptz)`, `'2010-09-28 00:00:00+00:00'`},
{`ANNOTATE_TYPE(123, int) + 1`, `124`},
Expand Down Expand Up @@ -645,78 +645,78 @@ func TestEval(t *testing.T) {
{`experimental_strptime('%y %m %d %M %S %H', '06 12 21 05 33 14')`, `'2006-12-21 14:05:33+00:00'`},
// Need two interval ops to verify the return type matches the return struct type.
{`'2010-09-28 12:00:00.1-04:00'::timestamptz - '0s'::interval - '0s'::interval`, `'2010-09-28 16:00:00.1+00:00'`},
{`'12h2m1s23ms'::interval + '1h'::interval`, `INTERVAL '13h2m1.023s'`},
{`'12 hours 2 minutes 1 second'::interval + '1h'::interval`, `INTERVAL '13h2m1s'`},
{`'PT12H2M1S'::interval + '1h'::interval`, `INTERVAL '13h2m1s'`},
{`'12:02:01'::interval + '1h'::interval`, `INTERVAL '13h2m1s'`},
{`'12h2m1s23ms'::interval - '1h'::interval`, `INTERVAL '11h2m1.023s'`},
{`'12 hours 2 minutes 1 second'::interval - '1h'::interval`, `INTERVAL '11h2m1s'`},
{`'PT12H2M1S'::interval - '1h'::interval`, `INTERVAL '11h2m1s'`},
{`'1h'::interval - '12h2m1s23ms'::interval`, `INTERVAL '-11h2m1.023s'`},
{`'PT1H'::interval - '12h2m1s23ms'::interval`, `INTERVAL '-11h2m1.023s'`},
{`'1 hour'::interval - '12h2m1s23ms'::interval`, `INTERVAL '-11h2m1.023s'`},
{`3 * '1h2m'::interval * 3`, `INTERVAL '9h18m0s'`},
{`3 * '1 hour 2 minutes'::interval * 3`, `INTERVAL '9h18m0s'`},
{`3 * 'PT1H2M'::interval * 3`, `INTERVAL '9h18m0s'`},
{`'3h'::interval / 2`, `INTERVAL '1h30m0s'`},
{`'PT3H'::interval / 2`, `INTERVAL '1h30m0s'`},
{`'3:00'::interval / 2`, `INTERVAL '1h30m0s'`},
{`'3 hours'::interval / 2`, `INTERVAL '1h30m0s'`},
{`'0:1'::interval`, `INTERVAL '1m0s'`},
{`'0:1.0'::interval`, `INTERVAL '1m0s'`},
{`'1'::interval`, `INTERVAL '1s'`},
{`'1.0:0:0'::interval`, `INTERVAL '1h0m0s'`},
{`'1.2'::interval`, `INTERVAL '1.2s'`},
{`'1.2:1:1.2'::interval`, `INTERVAL '1h13m1.2s'`},
{`'1:0:0'::interval`, `INTERVAL '1h0m0s'`},
{`'1:1.2'::interval`, `INTERVAL '1h1m12s'`},
{`'1:2'::interval`, `INTERVAL '1h2m0s'`},
{`'1:2.3'::interval`, `INTERVAL '1h2m18s'`},
{`'1:2:3'::interval`, `INTERVAL '1h2m3s'`},
{`'1234:56:54'::interval`, `INTERVAL '1234h56m54s'`},
{`'-0:1'::interval`, `INTERVAL '-1m0s'`},
{`'-0:1.0'::interval`, `INTERVAL '-1m0s'`},
{`'-1'::interval`, `INTERVAL '-1s'`},
{`'-1.0:0:0'::interval`, `INTERVAL '-1h0m0s'`},
{`'-1.2'::interval`, `INTERVAL '-1.2s'`},
{`'-1:0:0'::interval`, `INTERVAL '-1h0m0s'`},
{`'-1:1.2'::interval`, `INTERVAL '-1h1m12s'`},
{`'-1:2'::interval`, `INTERVAL '-1h2m0s'`},
{`'-1:2.3'::interval`, `INTERVAL '-1h2m18s'`},
{`'-1:2:3'::interval`, `INTERVAL '-1h2m3s'`},
{`'-1234:56:54'::interval`, `INTERVAL '-1234h56m54s'`},
{`'1-2'::interval`, `INTERVAL '14m0d0ns'`},
{`'-1-2'::interval`, `INTERVAL '-14m0d0ns'`},
{`'1-2 3'::interval`, `INTERVAL '14m0d3s'`},
{`'1-2 -3'::interval`, `INTERVAL '14m0d-3s'`},
{`'-1-2 -3'::interval`, `INTERVAL '-14m0d-3s'`},
{`'2 4:08'::interval`, `INTERVAL '0m2d4h8m0s'`},
{`'-2 4:08'::interval`, `INTERVAL '0m-2d4h8m0s'`},
{`'2 -4:08'::interval`, `INTERVAL '0m2d-4h8m0s'`},
{`'1-2 4:08'::interval`, `INTERVAL '14m0d4h8m0s'`},
{`'1-2 3 4:08'::interval`, `INTERVAL '14m3d4h8m0s'`},
{`'1-2 3 4:08:05'::interval`, `INTERVAL '14m3d4h8m5s'`},
{`'1-2 4:08:23'::interval`, `INTERVAL '14m0d4h8m23s'`},
{`'1- 4:08:23'::interval`, `INTERVAL '12m0d4h8m23s'`},
{`'0-2 3 4:08'::interval`, `INTERVAL '2m3d4h8m0s'`},
{`'1- 3 4:08:'::interval`, `INTERVAL '12m3d4h8m0s'`},
{`'-1- 3 4:08:'::interval`, `INTERVAL '-12m3d4h8m0s'`},
{`'0- 3 4:08'::interval`, `INTERVAL '0m3d4h8m0s'`},
{`'-0- 3 4:08'::interval`, `INTERVAL '0m3d4h8m0s'`},
{`'-0- -0 4:08'::interval`, `INTERVAL '4h8m0s'`},
{`'-0- -0 0:0'::interval`, `INTERVAL '0s'`},
{`'-0- -0 -0:0'::interval`, `INTERVAL '0s'`},
{`'-0- -3 -4:08'::interval`, `INTERVAL '0m-3d-4h8m0s'`},
{`'0- 3 4::08'::interval`, `INTERVAL '0m3d4h0m8s'`},
{`' 0- 3 4::08 '::interval`, `INTERVAL '0m3d4h0m8s'`},
{`'2 4:08:23'::interval`, `INTERVAL '0m2d4h8m23s'`},
{`'1-2 3 4:08:23'::interval`, `INTERVAL '14m3d4h8m23s'`},
{`'1-'::interval`, `INTERVAL '12m0d0ns'`},
{`'1- 2'::interval`, `INTERVAL '12m0d2s'`},
{`'2 3:'::interval`, `INTERVAL '0m2d3h0m0s'`},
{`'2 3:4:'::interval`, `INTERVAL '0m2d3h4m0s'`},
{`'1- 3:'::interval`, `INTERVAL '12m0d3h0m0s'`},
{`'1- 3:4'::interval`, `INTERVAL '12m0d3h4m0s'`},
{`'12h2m1s23ms'::interval + '1h'::interval`, `'13h2m1.023s'`},
{`'12 hours 2 minutes 1 second'::interval + '1h'::interval`, `'13h2m1s'`},
{`'PT12H2M1S'::interval + '1h'::interval`, `'13h2m1s'`},
{`'12:02:01'::interval + '1h'::interval`, `'13h2m1s'`},
{`'12h2m1s23ms'::interval - '1h'::interval`, `'11h2m1.023s'`},
{`'12 hours 2 minutes 1 second'::interval - '1h'::interval`, `'11h2m1s'`},
{`'PT12H2M1S'::interval - '1h'::interval`, `'11h2m1s'`},
{`'1h'::interval - '12h2m1s23ms'::interval`, `'-11h2m1.023s'`},
{`'PT1H'::interval - '12h2m1s23ms'::interval`, `'-11h2m1.023s'`},
{`'1 hour'::interval - '12h2m1s23ms'::interval`, `'-11h2m1.023s'`},
{`3 * '1h2m'::interval * 3`, `'9h18m0s'`},
{`3 * '1 hour 2 minutes'::interval * 3`, `'9h18m0s'`},
{`3 * 'PT1H2M'::interval * 3`, `'9h18m0s'`},
{`'3h'::interval / 2`, `'1h30m0s'`},
{`'PT3H'::interval / 2`, `'1h30m0s'`},
{`'3:00'::interval / 2`, `'1h30m0s'`},
{`'3 hours'::interval / 2`, `'1h30m0s'`},
{`'0:1'::interval`, `'1m0s'`},
{`'0:1.0'::interval`, `'1m0s'`},
{`'1'::interval`, `'1s'`},
{`'1.0:0:0'::interval`, `'1h0m0s'`},
{`'1.2'::interval`, `'1.2s'`},
{`'1.2:1:1.2'::interval`, `'1h13m1.2s'`},
{`'1:0:0'::interval`, `'1h0m0s'`},
{`'1:1.2'::interval`, `'1h1m12s'`},
{`'1:2'::interval`, `'1h2m0s'`},
{`'1:2.3'::interval`, `'1h2m18s'`},
{`'1:2:3'::interval`, `'1h2m3s'`},
{`'1234:56:54'::interval`, `'1234h56m54s'`},
{`'-0:1'::interval`, `'-1m0s'`},
{`'-0:1.0'::interval`, `'-1m0s'`},
{`'-1'::interval`, `'-1s'`},
{`'-1.0:0:0'::interval`, `'-1h0m0s'`},
{`'-1.2'::interval`, `'-1.2s'`},
{`'-1:0:0'::interval`, `'-1h0m0s'`},
{`'-1:1.2'::interval`, `'-1h1m12s'`},
{`'-1:2'::interval`, `'-1h2m0s'`},
{`'-1:2.3'::interval`, `'-1h2m18s'`},
{`'-1:2:3'::interval`, `'-1h2m3s'`},
{`'-1234:56:54'::interval`, `'-1234h56m54s'`},
{`'1-2'::interval`, `'14m0d0ns'`},
{`'-1-2'::interval`, `'-14m0d0ns'`},
{`'1-2 3'::interval`, `'14m0d3s'`},
{`'1-2 -3'::interval`, `'14m0d-3s'`},
{`'-1-2 -3'::interval`, `'-14m0d-3s'`},
{`'2 4:08'::interval`, `'0m2d4h8m0s'`},
{`'-2 4:08'::interval`, `'0m-2d4h8m0s'`},
{`'2 -4:08'::interval`, `'0m2d-4h8m0s'`},
{`'1-2 4:08'::interval`, `'14m0d4h8m0s'`},
{`'1-2 3 4:08'::interval`, `'14m3d4h8m0s'`},
{`'1-2 3 4:08:05'::interval`, `'14m3d4h8m5s'`},
{`'1-2 4:08:23'::interval`, `'14m0d4h8m23s'`},
{`'1- 4:08:23'::interval`, `'12m0d4h8m23s'`},
{`'0-2 3 4:08'::interval`, `'2m3d4h8m0s'`},
{`'1- 3 4:08:'::interval`, `'12m3d4h8m0s'`},
{`'-1- 3 4:08:'::interval`, `'-12m3d4h8m0s'`},
{`'0- 3 4:08'::interval`, `'0m3d4h8m0s'`},
{`'-0- 3 4:08'::interval`, `'0m3d4h8m0s'`},
{`'-0- -0 4:08'::interval`, `'4h8m0s'`},
{`'-0- -0 0:0'::interval`, `'0s'`},
{`'-0- -0 -0:0'::interval`, `'0s'`},
{`'-0- -3 -4:08'::interval`, `'0m-3d-4h8m0s'`},
{`'0- 3 4::08'::interval`, `'0m3d4h0m8s'`},
{`' 0- 3 4::08 '::interval`, `'0m3d4h0m8s'`},
{`'2 4:08:23'::interval`, `'0m2d4h8m23s'`},
{`'1-2 3 4:08:23'::interval`, `'14m3d4h8m23s'`},
{`'1-'::interval`, `'12m0d0ns'`},
{`'1- 2'::interval`, `'12m0d2s'`},
{`'2 3:'::interval`, `'0m2d3h0m0s'`},
{`'2 3:4:'::interval`, `'0m2d3h4m0s'`},
{`'1- 3:'::interval`, `'12m0d3h0m0s'`},
{`'1- 3:4'::interval`, `'12m0d3h4m0s'`},
// Conditional expressions.
{`IF(true, 1, 2/0)`, `1`},
{`IF(false, 1/0, 2)`, `2`},
Expand Down
25 changes: 13 additions & 12 deletions pkg/sql/parser/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1004,8 +1004,7 @@ type castSyntaxMode int
const (
castExplicit castSyntaxMode = iota
castShort
castPrefix
castPrefixParens
castPrepend
)

// CastTargetType represents a type that is a valid cast target.
Expand Down Expand Up @@ -1051,19 +1050,21 @@ type CastExpr struct {
// Format implements the NodeFormatter interface.
func (node *CastExpr) Format(buf *bytes.Buffer, f FmtFlags) {
switch node.syntaxMode {
case castPrepend:
// This is a special case for things like INTERVAL '1s'. These only work
// with string constats; if the underlying expression was changed, we fall
// back to the short syntax.
if _, ok := node.Expr.(*StrVal); ok {
FormatNode(buf, f, node.Type)
buf.WriteByte(' ')
FormatNode(buf, f, node.Expr)
break
}
fallthrough
case castShort:
FormatNode(buf, f, node.Expr)
buf.WriteString("::")
FormatNode(buf, f, node.Type)
case castPrefix:
FormatNode(buf, f, node.Type)
buf.WriteByte(' ')
FormatNode(buf, f, node.Expr)
case castPrefixParens:
FormatNode(buf, f, node.Type)
buf.WriteString(" (")
FormatNode(buf, f, node.Expr)
buf.WriteByte(')')
default:
buf.WriteString("CAST(")
FormatNode(buf, f, node.Expr)
Expand Down Expand Up @@ -1153,7 +1154,6 @@ type AnnotateTypeExpr struct {
Expr Expr
Type CastTargetType

typeAnnotation
syntaxMode annotateSyntaxMode
}

Expand All @@ -1164,6 +1164,7 @@ func (node *AnnotateTypeExpr) Format(buf *bytes.Buffer, f FmtFlags) {
FormatNode(buf, f, node.Expr)
buf.WriteString(":::")
FormatNode(buf, f, node.Type)

default:
buf.WriteString("ANNOTATE_TYPE(")
FormatNode(buf, f, node.Expr)
Expand Down
Loading

0 comments on commit 5f87a27

Please sign in to comment.