Skip to content

Commit

Permalink
Add support for Postgres Range types. Closes cockroachdb#27791
Browse files Browse the repository at this point in the history
  • Loading branch information
faith0811 committed Aug 28, 2018
1 parent 9ff5d55 commit c8c5d84
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 1 deletion.
11 changes: 11 additions & 0 deletions pkg/sql/coltypes/aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ var (
// JSON is an immutable T instance.
JSON = &TJSON{}

// INT4RANGE is an immutable T instance.
Int4Range = &TRange{Int4}
// INT8RANGE is an immutable T instance.
Int8Range = &TRange{Int8}
// NUMRANGE is an immutable T instance.
NumRange = &TRange{Decimal}
// INT4RANGE is an immutable T instance.
TSRange = &TRange{Timestamp}
// INT4RANGE is an immutable T instance.
TSTZRange = &TRange{TimestampWithTZ}

// Oid is an immutable T instance.
Oid = &TOid{Name: "OID"}
// RegClass is an immutable T instance.
Expand Down
46 changes: 46 additions & 0 deletions pkg/sql/coltypes/ranges.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2017 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

package coltypes

import (
"bytes"
"github.com/cockroachdb/cockroach/pkg/sql/lex"
)

// TRange represents a XXXRANGE column type.
type TRange struct {
ParamType T
}

// TypeName implements the ColTypeFormatter interface.
func (node *TRange) TypeName() string {
return node.ParamType.TypeName() + "RANGE"
}

// Format implements the ColTypeFormatter interface.
func (node *TRange) Format(buf *bytes.Buffer, f lex.EncodeFlags) {
buf.WriteString(node.TypeName())
}

func canBeInRangeColType(t T) bool {
// TODO: Any column type with b-tree operator can be customized with range col type,
// TODO: But for now we just impl the builtin ones.
switch t.(type) {
case *TInt, *TDecimal, *TTimestamp, *TTimestampTZ:
return true
default:
return false
}
}
27 changes: 27 additions & 0 deletions pkg/sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -6297,6 +6297,28 @@ interval_second:
}
| SECOND '(' ICONST ')' { return unimplemented(sqllex, "interval_second") }

range_types:
INT4RANGE
{
$$.val = coltypes.Int4Range
}
| INT8RANGE
{
$$.val = coltypes.Int8Range
}
| NUMRANGE
{
$$.val = coltypes.NumRange
}
| TSRANGE
{
$$.val = coltypes.TSRange
}
| TSTZRANGE
{
$$.val = coltypes.TSTZRange
}

// General expressions. This is the heart of the expression syntax.
//
// We have two expression types: a_expr is the unrestricted kind, and b_expr is
Expand Down Expand Up @@ -8397,12 +8419,15 @@ col_name_keyword:
| IFERROR
| IFNULL
| INT
| INT4RANGE
| INT8RANGE
| INTEGER
| INTERVAL
| ISERROR
| LEAST
| NULLIF
| NUMERIC
| NUMRANGE
| OUT
| OVERLAY
| POSITION
Expand All @@ -8414,6 +8439,8 @@ col_name_keyword:
| TIME
| TIMETZ
| TIMESTAMP
| TSRANGE
| TSTZRANGE
| TREAT
| TRIM
| VALUES
Expand Down
3 changes: 2 additions & 1 deletion pkg/sql/pg_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -1775,7 +1775,6 @@ var (
_ = typCategoryComposite
_ = typCategoryEnum
_ = typCategoryGeometric
_ = typCategoryRange
_ = typCategoryBitString
_ = typCategoryUnknown

Expand Down Expand Up @@ -2076,6 +2075,8 @@ func typCategory(typ types.T) tree.Datum {
return typCategoryPseudo
}
return typCategoryArray
} else if typ.FamilyEqual(types.FamRange) {
return typCategoryRange
}
return datumToTypeCategory[reflect.TypeOf(types.UnwrapType(typ))]
}
Expand Down
55 changes: 55 additions & 0 deletions pkg/sql/sem/tree/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -3005,6 +3005,61 @@ func (d *DArray) Append(v Datum) error {
return d.Validate()
}

type DRange struct {
ParamTyp types.T

Lower Datum
Upper Datum

BlanketType int
}

func (d *DRange) AmbiguousFormat() bool {
return false
}

func (d *DRange) Compare(ctx *EvalContext, other Datum) int {
return 1
}

func (d *DRange) Prev(ctx *EvalContext) (Datum, bool) {
return nil, false
}

func (d *DRange) IsMin(ctx *EvalContext) bool {
return false
}

func (d *DRange) Next(ctx *EvalContext) (Datum, bool) {
return nil, false
}

func (d *DRange) IsMax(ctx *EvalContext) bool {
return false
}

func (d *DRange) Max(ctx *EvalContext) (Datum, bool) {
return nil, false
}

func (d *DRange) Min(ctx *EvalContext) (Datum, bool) {
return nil, false
}

func (d *DRange) Size() uintptr {
return unsafe.Sizeof(*d)
}

// ResolvedType implements the TypedExpr interface.
func (d *DRange) ResolvedType() types.T {
return types.TRange{Typ: d.ParamTyp}
}

// Format implements the NodeFormatter interface
func (d *DRange) Format(ctx *FmtCtx) {

}

// DOid is the Postgres OID datum. It can represent either an OID type or any
// of the reg* types, such as regproc or regclass.
type DOid struct {
Expand Down
5 changes: 5 additions & 0 deletions pkg/sql/sem/tree/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -3782,6 +3782,11 @@ func (t *DOid) Eval(_ *EvalContext) (Datum, error) {
return t, nil
}

// Eval implements the TypedExpr interface.
func (t *DRange) Eval(_ *EvalContext) (Datum, error) {
return t, nil
}

// Eval implements the TypedExpr interface.
func (t *DOidWrapper) Eval(_ *EvalContext) (Datum, error) {
return t, nil
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/sem/tree/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,7 @@ func (node *DTimestamp) String() string { return AsString(node) }
func (node *DTimestampTZ) String() string { return AsString(node) }
func (node *DTuple) String() string { return AsString(node) }
func (node *DArray) String() string { return AsString(node) }
func (node *DRange) String() string { return AsString(node) }
func (node *DOid) String() string { return AsString(node) }
func (node *DOidWrapper) String() string { return AsString(node) }
func (node *Exprs) String() string { return AsString(node) }
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/sem/tree/type_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,10 @@ func (d *DTuple) TypeCheck(_ *SemaContext, _ types.T) (TypedExpr, error) { retur
// identity function for Datum.
func (d *DArray) TypeCheck(_ *SemaContext, _ types.T) (TypedExpr, error) { return d, nil }

// TypeCheck implements the Expr interface. It is implemented as an idempotent
// identity function for Datum.
func (d *DRange) TypeCheck(_ *SemaContext, _ types.T) (TypedExpr, error) { return d, nil }

// TypeCheck implements the Expr interface. It is implemented as an idempotent
// identity function for Datum.
func (d *DOid) TypeCheck(_ *SemaContext, _ types.T) (TypedExpr, error) { return d, nil }
Expand Down
3 changes: 3 additions & 0 deletions pkg/sql/sem/tree/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,9 @@ func (expr *DTuple) Walk(_ Visitor) Expr { return expr }
// Walk implements the Expr interface.
func (expr *DArray) Walk(_ Visitor) Expr { return expr }

// Walk implements the Expr interface.
func (expr *DRange) Walk(_ Visitor) Expr { return expr }

// Walk implements the Expr interface.
func (expr *DOid) Walk(_ Visitor) Expr { return expr }

Expand Down
15 changes: 15 additions & 0 deletions pkg/sql/sem/types/oid.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ var oidToArrayOid = map[oid.Oid]oid.Oid{
oid.T_timestamptz: oid.T__timestamptz,
oid.T_varchar: oid.T__varchar,
oid.T_uuid: oid.T__uuid,
oid.T_int4range: oid.T__int4range,
oid.T_int8range: oid.T__int8range,
oid.T_tsrange: oid.T__tsrange,
oid.T_tstzrange: oid.T__tstzrange,
oid.T_daterange: oid.T__daterange,
oid.T_numrange: oid.T__numrange,
}

var oidToRangeOid = map[oid.Oid]oid.Oid{
oid.T_int4: oid.T_int4range,
oid.T_int8: oid.T_int8range,
oid.T_timestamp: oid.T_tsrange,
oid.T_timestamptz: oid.T_tstzrange,
oid.T_date: oid.T_daterange,
oid.T_numeric: oid.T_numrange,
}

// TOid represents an alias to the Int type with a different Postgres OID.
Expand Down
42 changes: 42 additions & 0 deletions pkg/sql/sem/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ var (
FamTuple T = TTuple{}
// FamArray is the type family of a DArray. CANNOT be compared with ==.
FamArray T = TArray{}
// FamRange is the type family of a DRange. CANNOT be compared with ==.
FamRange T = TRange{}
// FamPlaceholder is the type family of a placeholder. CANNOT be compared
// with ==.
FamPlaceholder T = TPlaceholder{}
Expand Down Expand Up @@ -466,6 +468,46 @@ func (a TArray) IsAmbiguous() bool {
return a.Typ == nil || a.Typ.IsAmbiguous()
}

type TRange struct {
Typ T
}

const noRangeType = 0

func (a TRange) String() string {
return ""
}

func (a TRange) Equivalent(other T) bool {
if other == Any {
return true
}
if u, ok := UnwrapType(other).(TRange); ok {
return a.Typ.Equivalent(u.Typ)
}
return false
}

func (TRange) FamilyEqual(other T) bool {
_, ok := UnwrapType(other).(TRange)
return ok
}

func (a TRange) Oid() oid.Oid {
if o, ok := oidToRangeOid[a.Typ.Oid()]; ok {
return o
}
return noRangeType
}

func (a TRange) SQLName() string {
return a.String()
}

func (a TRange) IsAmbiguous() bool {
return a.Typ == nil || a.Typ.IsAmbiguous()
}

type tAny struct{}

func (tAny) String() string { return "anyelement" }
Expand Down
13 changes: 13 additions & 0 deletions pkg/sql/sqlbase/datum_alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type DatumAlloc struct {
djsonAlloc []tree.DJSON
dtupleAlloc []tree.DTuple
doidAlloc []tree.DOid
drangeAlloc []tree.DRange
scratch []byte
env tree.CollationEnvironment
}
Expand Down Expand Up @@ -241,3 +242,15 @@ func (a *DatumAlloc) NewDOid(v tree.DOid) tree.Datum {
*buf = (*buf)[1:]
return r
}

// NewDRange allocates a DRange.
func (a *DatumAlloc) NewDRange(v tree.DRange) tree.Datum {
buf := &a.drangeAlloc
if len(*buf) == 0 {
*buf = make([]tree.DRange, datumAllocSize)
}
r := &(*buf)[0]
*r = v
*buf = (*buf)[1:]
return r
}

0 comments on commit c8c5d84

Please sign in to comment.