Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unsupported data types #95

Merged
merged 4 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ os:
- linux

go:
- 1.11.x
- 1.12.x
- 1.13.x
- 1.14.x
- 1.15.x
- master

go_import_path: github.com/vertica/vertica-sql-go
Expand All @@ -31,4 +32,4 @@ script:
- go test -race . -args --locator localhost:5433 --user dbadmin --tlsmode=server
- go test -race . -args --locator localhost:5433 --user dbadmin --tlsmode=server --use_prepared_statements=0
# go test --locator localhost:5433 --user dbadmin --tlsmode=server-strict -race .
# go test --locator localhost:5433 --user dbadmin --tlsmode=server-strict --use_prepared_statements=0 -race .
# go test --locator localhost:5433 --user dbadmin --tlsmode=server-strict --use_prepared_statements=0 -race .
19 changes: 17 additions & 2 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,13 @@ const (
ColTypeFloat64 uint32 = 7
ColTypeChar uint32 = 8
ColTypeVarChar uint32 = 9
ColTypeDate uint32 = 10
ColTypeTime uint32 = 11
ColTypeTimestamp uint32 = 12
ColTypeTimestampTZ uint32 = 13
ColTypeInterval uint32 = 14
ColTypeIntervalYM uint32 = 114
ColTypeTimeTZ uint32 = 15
ColTypeNumeric uint32 = 16
ColTypeVarBinary uint32 = 17
ColTypeUUID uint32 = 20
Expand Down Expand Up @@ -77,10 +82,22 @@ func ColumnTypeString(typeOID uint32) string {
return "char"
case ColTypeVarChar:
return "varchar"
case ColTypeDate:
return "date"
case ColTypeTime:
return "time"
case ColTypeTimestamp:
return "timestamp"
case ColTypeTimestampTZ:
return "timestamptz"
case ColTypeInterval:
return "interval"
case ColTypeIntervalYM:
return "intervalym"
case ColTypeTimeTZ:
return "timetz"
case ColTypeNumeric:
return "numeric"
case ColTypeVarBinary:
return "varbinary"
case ColTypeUUID:
Expand All @@ -91,8 +108,6 @@ func ColumnTypeString(typeOID uint32) string {
return "long varbinary"
case ColTypeBinary:
return "binary"
case ColTypeNumeric:
return "numeric"
}

return fmt.Sprintf("unknown column type oid: %d", typeOID)
Expand Down
56 changes: 49 additions & 7 deletions driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,16 @@ func TestSHA512Authentication(t *testing.T) {
testAnAuthScheme(t, "SHA512")
}

func TestDateParsers(t *testing.T) {
val, err := parseDateColumn("2018-02-01")
assertNoErr(t, err)
assertEqual(t, fmt.Sprintf("%s", val)[0:10], "2018-02-01")

val, err = parseDateColumn("2018-02-01 BC")
assertNoErr(t, err)
assertEqual(t, fmt.Sprintf("%s", val)[0:11], "-2018-02-01")
}

func TestTimestampParsers(t *testing.T) {
val, err := parseTimestampTZColumn("2018-02-01 21:09:33.1234+00")
assertNoErr(t, err)
Expand All @@ -472,6 +482,14 @@ func TestTimestampParsers(t *testing.T) {
val, err = parseTimestampTZColumn("2018-01-27 21:09:44+00")
assertNoErr(t, err)
assertEqual(t, fmt.Sprintf("%s", val)[0:25], "2018-01-27 21:09:44 +0000")

val, err = parseTimestampTZColumn("2018-01-27 21:09:44+10 BC")
assertNoErr(t, err)
assertEqual(t, fmt.Sprintf("%s", val)[0:26], "-2018-01-27 21:09:44 +1000")

val, err = parseTimestampTZColumn("2018-01-27 21:09:44.843913 BC-04")
assertNoErr(t, err)
assertEqual(t, fmt.Sprintf("%s", val)[0:33], "-2018-01-27 21:09:44.843913 -0400")
}

func TestEmptyStatementError(t *testing.T) {
Expand All @@ -497,8 +515,13 @@ func TestValueTypes(t *testing.T) {
floatVal float64
charVal string
varCharVal string
timestampVal string
timestampTZVal string
dateVal time.Time
timestampVal time.Time
timestampTZVal time.Time
intervalVal string
intervalYMVal string
timeVal time.Time
timeTZVal time.Time
varBinVal string
uuidVal string
lVarCharVal string
Expand All @@ -510,13 +533,21 @@ func TestValueTypes(t *testing.T) {
rows, err := connDB.QueryContext(ctx, "SELECT * FROM full_type_table")
assertNoErr(t, err)
assertNext(t, rows)
assertNoErr(t, rows.Scan(&boolVal, &intVal, &floatVal, &charVal, &varCharVal, &timestampVal, &timestampTZVal,
assertNoErr(t, rows.Scan(&boolVal, &intVal, &floatVal, &charVal, &varCharVal, &dateVal,
&timestampVal, &timestampTZVal, &intervalVal, &intervalYMVal, &timeVal, &timeTZVal,
&varBinVal, &uuidVal, &lVarCharVal, &lVarBinaryVal, &binaryVal, &numericVal))
assertEqual(t, boolVal, true)
assertEqual(t, intVal, 123)
assertEqual(t, floatVal, 3.141)
assertEqual(t, charVal, "a")
assertEqual(t, varCharVal, "test values")
assertEqual(t, dateVal.String()[0:10], "1999-01-08")
assertEqual(t, timestampVal.String()[0:26], "2019-08-04 00:45:19.843913")
assertEqual(t, timestampTZVal.UTC().String()[0:32], "2019-08-04 04:45:19.843913 +0000")
assertEqual(t, intervalVal, "-6537150 01:03:06.0051")
assertEqual(t, intervalYMVal, "1-2")
assertEqual(t, timeVal.String()[11:23], "04:05:06.789")
assertEqual(t, timeTZVal.String()[11:25], "16:05:06 -0800")
assertEqual(t, varBinVal, "5c3237365c3335375c3333365c323535")
assertEqual(t, uuidVal, "372fd680-6a72-4003-96b0-10bbe78cd635")
assertEqual(t, lVarCharVal, "longer var char")
Expand All @@ -532,8 +563,13 @@ func TestValueTypes(t *testing.T) {
nullFloatVal sql.NullFloat64
nullCharVal sql.NullString
nullVarCharVal sql.NullString
nullTimestampVal sql.NullString
nullTimestampTZVal sql.NullString
nullDateVal sql.NullTime
nullTimestampVal sql.NullTime
nullTimestampTZVal sql.NullTime
nullIntervalVal sql.NullString
nullIntervalYMVal sql.NullString
nullTimeVal sql.NullTime
nullTimeTZVal sql.NullTime
nullVarBinVal sql.NullString
nullUuidVal sql.NullString
nullLVarCharVal sql.NullString
Expand All @@ -543,16 +579,22 @@ func TestValueTypes(t *testing.T) {
)

assertNoErr(t, rows.Scan(&nullBoolVal, &nullIntVal, &nullFloatVal, &nullCharVal,
&nullVarCharVal, &nullTimestampVal, &nullTimestampTZVal, &nullVarBinVal, &nullUuidVal,
&nullLVarCharVal, &nullLVarBinaryVal, &nullBinaryVal, &nullNumericVal))
&nullVarCharVal, &nullDateVal, &nullTimestampVal, &nullTimestampTZVal,
&nullIntervalVal, &nullIntervalYMVal, &nullTimeVal, &nullTimeTZVal, &nullVarBinVal,
&nullUuidVal, &nullLVarCharVal, &nullLVarBinaryVal, &nullBinaryVal, &nullNumericVal))

assertTrue(t, !nullBoolVal.Valid)
assertTrue(t, !nullIntVal.Valid)
assertTrue(t, !nullFloatVal.Valid)
assertTrue(t, !nullCharVal.Valid)
assertTrue(t, !nullVarCharVal.Valid)
assertTrue(t, !nullDateVal.Valid)
assertTrue(t, !nullTimestampVal.Valid)
assertTrue(t, !nullTimestampTZVal.Valid)
assertTrue(t, !nullIntervalVal.Valid)
assertTrue(t, !nullIntervalYMVal.Valid)
assertTrue(t, !nullTimeVal.Valid)
assertTrue(t, !nullTimeTZVal.Valid)
assertTrue(t, !nullVarBinVal.Valid)
assertTrue(t, !nullUuidVal.Valid)
assertTrue(t, !nullLVarCharVal.Valid)
Expand Down
11 changes: 9 additions & 2 deletions resources/tests/driver_test/test_value_types_pre.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ intVal INT,
floatVal FLOAT,
charVal CHAR,
varCharVal VARCHAR(128),
dateVal DATE,
timestampVal TIMESTAMP,
timestampTZVal TIMESTAMPTZ,
intervalVal INTERVAL DAY TO SECOND(4),
intervalYMVal INTERVAL YEAR TO MONTH,
timeVal TIME,
timeTZVal TIMETZ,
varBinVal VARBINARY,
uuidVal UUID,
lVarCharVal LONG VARCHAR(65536),
Expand All @@ -19,8 +24,10 @@ numericVal NUMERIC
);

INSERT INTO full_type_table VALUES(
true, 123, 3.141, 'a', 'test values', '2019-08-04T00:45:19.843913-04:00', '2019-08-04T00:45:19.843913-04:00',
true, 123, 3.141, 'a', 'test values', '1999-Jan-08', '2019-08-04 00:45:19.843913', '2019-08-04 00:45:19.843913 -04:00',
'17910y 1h 3m 6s 5msecs 57us ago', '1 2', '04:05:06.789', '04:05:06-8:00 PM',
HEX_TO_BINARY('beefdead')::VARBINARY, '372fd680-6a72-4003-96b0-10bbe78cd635', 'longer var char',
HEX_TO_BINARY('deadbeef')::LONG VARBINARY,HEX_TO_BINARY('baadf00d'), 1.2345);

INSERT INTO full_type_table VALUES(null, null, null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO full_type_table VALUES(null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null);
41 changes: 41 additions & 0 deletions rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"context"
"database/sql/driver"
"encoding/hex"
"fmt"
"io"
"regexp"
"strconv"
Expand Down Expand Up @@ -111,10 +112,18 @@ func (r *rows) Next(dest []driver.Value) error {
dest[idx] = string(colVal)
case common.ColTypeFloat64, common.ColTypeNumeric: // to float64
dest[idx], err = strconv.ParseFloat(string(colVal), 64)
case common.ColTypeDate: // to time.Time from YYYY-MM-DD
dest[idx], err = parseDateColumn(string(colVal))
case common.ColTypeTimestamp: // to time.Time from YYYY-MM-DD hh:mm:ss
dest[idx], err = parseTimestampTZColumn(string(colVal) + r.tzOffset)
case common.ColTypeTimestampTZ:
dest[idx], err = parseTimestampTZColumn(string(colVal))
case common.ColTypeTime: // to time.Time from hh:mm:ss.[fff...]
dest[idx], err = parseTimestampTZColumn("0000-01-01 " + string(colVal) + r.tzOffset)
case common.ColTypeTimeTZ:
dest[idx], err = parseTimestampTZColumn("0000-01-01 " + string(colVal))
case common.ColTypeInterval, common.ColTypeIntervalYM: // stays string
dest[idx] = string(colVal)
case common.ColTypeVarBinary, common.ColTypeLongVarBinary, common.ColTypeBinary: // to []byte - this one's easy
dest[idx] = hex.EncodeToString(colVal)
default:
Expand All @@ -129,9 +138,37 @@ func (r *rows) Next(dest []driver.Value) error {
return err
}

func parseDateColumn(fullString string) (driver.Value, error) {
var result driver.Value
var err error

// Dates Before Christ (YYYY-MM-DD BC) are special
if strings.HasSuffix(fullString, " BC") {
var t time.Time
t, err = time.Parse("2006-01-02 BC", fullString)
if err != nil {
return time.Time{}, err
}
result = t.AddDate(-2*t.Year(), 0, 0)
} else {
result, err = time.Parse("2006-01-02", fullString)
}
return result, err
}

func parseTimestampTZColumn(fullString string) (driver.Value, error) {
var result driver.Value
var err error
var isBC bool

// +infinity or -infinity value
if strings.Contains(fullString, "infinity") {
return time.Time{}, fmt.Errorf("cannot parse an infinity timestamp to time.Time")
}

if isBC = strings.Contains(fullString, " BC"); isBC {
fullString = strings.Replace(fullString, " BC", "", -1)
}

endsWithHalfHour, _ := regexp.Compile(".*:\\d{2}$")
if !endsWithHalfHour.MatchString(fullString) {
Expand All @@ -148,7 +185,11 @@ func parseTimestampTZColumn(fullString string) (driver.Value, error) {
fullString = fullString[0:19] + "." + paddingString[0:6] + fullString[19:]
}

// Note: The date/time output format for the current session (sql=> SHOW DATESTYLE) should be 'ISO'
result, err = time.Parse("2006-01-02 15:04:05.000000-07:00", fullString)
if isBC {
result = result.(time.Time).AddDate(-2*result.(time.Time).Year(), 0, 0)
}

return result, err
}
Expand Down