Add support for Timestamp data type in SQL Select (#7185)

This change adds support for casting strings to Timestamp via CAST:
`CAST('2010T' AS TIMESTAMP)`

It also implements the following date-time functions:
  - UTCNOW()
  - DATE_ADD()
  - DATE_DIFF()
  - EXTRACT()

For values passed to these functions, date-types are automatically
inferred.
This commit is contained in:
Aditya Manthramurthy
2019-02-04 20:54:45 -08:00
committed by kannappanr
parent ea6d61ab1f
commit f04f8bbc78
10 changed files with 514 additions and 35 deletions

View File

@@ -22,6 +22,7 @@ import (
"math"
"strconv"
"strings"
"time"
)
var (
@@ -48,6 +49,9 @@ const (
// 64-bit floating point
typeFloat
// timestamp type
typeTimestamp
// This type refers to untyped values, e.g. as read from CSV
typeBytes
)
@@ -77,6 +81,8 @@ func (v *Value) GetTypeString() string {
return "INT"
case typeFloat:
return "FLOAT"
case typeTimestamp:
return "TIMESTAMP"
case typeBytes:
return "BYTES"
}
@@ -90,6 +96,8 @@ func (v *Value) Repr() string {
return ":NULL"
case typeBool, typeInt, typeFloat:
return fmt.Sprintf("%v:%s", v.value, v.GetTypeString())
case typeTimestamp:
return fmt.Sprintf("%s:TIMESTAMP", v.value.(*time.Time))
case typeString:
return fmt.Sprintf("\"%s\":%s", v.value.(string), v.GetTypeString())
case typeBytes:
@@ -119,6 +127,11 @@ func FromBool(b bool) *Value {
return &Value{value: b, vType: typeBool}
}
// FromTimestamp creates a Value from a timestamp
func FromTimestamp(t time.Time) *Value {
return &Value{value: t, vType: typeTimestamp}
}
// FromNull creates a Value with Null value
func FromNull() *Value {
return &Value{vType: typeNull}
@@ -173,6 +186,15 @@ func (v *Value) ToBool() (val bool, ok bool) {
return false, false
}
// ToTimestamp returns the timestamp value if present.
func (v *Value) ToTimestamp() (t time.Time, ok bool) {
switch v.vType {
case typeTimestamp:
return v.value.(time.Time), true
}
return t, false
}
// ToBytes converts Value to byte-slice.
func (v *Value) ToBytes() ([]byte, bool) {
switch v.vType {
@@ -213,6 +235,11 @@ func (v *Value) setBool(b bool) {
v.value = b
}
func (v *Value) setTimestamp(t time.Time) {
v.vType = typeTimestamp
v.value = t
}
// CSVString - convert to string for CSV serialization
func (v *Value) CSVString() string {
switch v.vType {
@@ -226,6 +253,8 @@ func (v *Value) CSVString() string {
return fmt.Sprintf("%v", v.value.(int64))
case typeFloat:
return fmt.Sprintf("%v", v.value.(float64))
case typeTimestamp:
return FormatSQLTimestamp(v.value.(time.Time))
case typeBytes:
return fmt.Sprintf("%v", string(v.value.([]byte)))
default:
@@ -242,6 +271,16 @@ func floatToValue(f float64) *Value {
return FromFloat(f)
}
// negate negates a numeric value
func (v *Value) negate() {
switch v.vType {
case typeFloat:
v.value = -(v.value.(float64))
case typeInt:
v.value = -(v.value.(int64))
}
}
// Value comparison functions: we do not expose them outside the
// module. Logical operators "<", ">", ">=", "<=" work on strings and
// numbers. Equality operators "=", "!=" work on strings,
@@ -571,6 +610,24 @@ func (v *Value) minmax(a *Value, isMax, isFirstRow bool) error {
return nil
}
func inferTypeAsTimestamp(v *Value) {
if s, ok := v.ToString(); ok {
t, err := parseSQLTimestamp(s)
if err != nil {
return
}
v.setTimestamp(t)
} else if b, ok := v.ToBytes(); ok {
s := string(b)
t, err := parseSQLTimestamp(s)
if err != nil {
return
}
v.setTimestamp(t)
}
return
}
// inferTypeAsString is used to convert untyped values to string - it
// is called when the caller requires a string context to proceed.
func inferTypeAsString(v *Value) {