Skip to content

Commit

Permalink
Merge pull request #42918 from otan-cockroach/backport19.2-42762
Browse files Browse the repository at this point in the history
release-19.2: sql: fix parsing of 0000-01-01 as Time/TimeTZ
  • Loading branch information
otan authored Dec 10, 2019
2 parents 36db1f3 + c09280f commit fa0782d
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 3 deletions.
13 changes: 13 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/time
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,16 @@ SELECT extract(epoch from time '12:00:00')

query error pgcode 22023 extract\(\): unsupported timespan: day
SELECT extract(day from time '12:00:00')

subtest regression_42749

# cast to string to prove it is 24:00
query T
SELECT '0000-01-01 24:00:00'::time::string
----
24:00:00

query T
SELECT '2001-01-01 01:24:00'::time
----
0000-01-01 01:24:00 +0000 UTC
8 changes: 5 additions & 3 deletions pkg/sql/sem/tree/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ var (
DZero = NewDInt(0)

// DTimeRegex is a compiled regex for parsing the 24:00 time value
DTimeRegex = regexp.MustCompile("^24:00($|(:00$)|(:00.0+$))")
DTimeRegex = regexp.MustCompile(`^([0-9-]*(\s|T))?\s*24:00(:00(.0+)?)?\s*$`)
)

// Datum represents a SQL value.
Expand Down Expand Up @@ -1864,13 +1864,15 @@ func MakeDTime(t timeofday.TimeOfDay) *DTime {
func ParseDTime(ctx ParseTimeContext, s string) (*DTime, error) {
now := relativeParseTime(ctx)

// special case on 24:00 and 24:00:00 as the parser
// Special case on 24:00 and 24:00:00 as the parser
// does not handle these correctly.
if DTimeRegex.MatchString(s) {
return MakeDTime(timeofday.Time2400), nil
}

t, err := pgdate.ParseTime(now, 0 /* mode */, s)
s = timeutil.ReplaceLibPQTimePrefix(s)

t, err := pgdate.ParseTime(now, pgdate.ParseModeYMD, s)
if err != nil {
// Build our own error message to avoid exposing the dummy date.
return nil, makeParseError(s, types.Time, nil)
Expand Down
9 changes: 9 additions & 0 deletions pkg/sql/sem/tree/datum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,13 +485,22 @@ func TestParseDTime(t *testing.T) {
str string
expected timeofday.TimeOfDay
}{
{" 04:05:06 ", timeofday.New(4, 5, 6, 0)},
{"04:05:06", timeofday.New(4, 5, 6, 0)},
{"04:05:06.000001", timeofday.New(4, 5, 6, 1)},
{"04:05:06-07", timeofday.New(4, 5, 6, 0)},
{"4:5:6", timeofday.New(4, 5, 6, 0)},
{"24:00:00", timeofday.Time2400},
{"24:00:00.000", timeofday.Time2400},
{"24:00:00.000000", timeofday.Time2400},
{"0000-01-01 04:05:06", timeofday.New(4, 5, 6, 0)},
{"2001-01-01 04:05:06", timeofday.New(4, 5, 6, 0)},
{"0000-01-01T04:05:06", timeofday.New(4, 5, 6, 0)},
{"0000-01-01T24:00:00", timeofday.Time2400},
{"0000-01-01 24:00:00", timeofday.Time2400},
{"0000-01-01 24:00:00.0", timeofday.Time2400},
{" 24:00:00.0", timeofday.Time2400},
{" 24:00:00.0 ", timeofday.Time2400},
}
for _, td := range testData {
actual, err := tree.ParseDTime(nil, td.str)
Expand Down
13 changes: 13 additions & 0 deletions pkg/util/timeutil/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package timeutil

import (
"math"
"strings"
"time"
)

Expand All @@ -20,6 +21,9 @@ import (
// assuming any bound on the clock drift.
const ClocklessMaxOffset = math.MaxInt64

// LibPQTimePrefix is the prefix lib/pq prints time-type datatypes with.
const LibPQTimePrefix = "0000-01-01"

// Since returns the time elapsed since t.
// It is shorthand for Now().Sub(t).
func Since(t time.Time) time.Duration {
Expand Down Expand Up @@ -72,3 +76,12 @@ func SleepUntil(untilNanos int64, currentTimeNanos func() int64) {
time.Sleep(d)
}
}

// ReplaceLibPQTimePrefix replaces unparsable lib/pq dates used for timestamps
// (0000-01-01) with timestamps that can be parsed by date libraries.
func ReplaceLibPQTimePrefix(s string) string {
if strings.HasPrefix(s, LibPQTimePrefix) {
return "1970-01-01" + s[len(LibPQTimePrefix):]
}
return s
}
7 changes: 7 additions & 0 deletions pkg/util/timeutil/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"math/rand"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestUnixMicros(t *testing.T) {
Expand Down Expand Up @@ -63,3 +65,8 @@ func TestUnixMicrosRounding(t *testing.T) {
}
}
}

func TestReplaceLibPQTimePrefix(t *testing.T) {
assert.Equal(t, "1970-02-02 11:00", ReplaceLibPQTimePrefix("1970-02-02 11:00"))
assert.Equal(t, "1970-01-01 11:00", ReplaceLibPQTimePrefix("0000-01-01 11:00"))
}

0 comments on commit fa0782d

Please sign in to comment.