diff --git a/pkg/sql/logictest/testdata/logic_test/datetime b/pkg/sql/logictest/testdata/logic_test/datetime index 024fa9b63d60..96aefd0928c8 100644 --- a/pkg/sql/logictest/testdata/logic_test/datetime +++ b/pkg/sql/logictest/testdata/logic_test/datetime @@ -1229,3 +1229,24 @@ query T SELECT '-5-12-26'::DATE ---- -0005-12-26 00:00:00 +0000 +0000 + +subtest regression_36146 + +query T +WITH + w (c) AS (VALUES (NULL), (NULL)) +SELECT + '1971-03-18'::DATE + 300866802885581286 +FROM + w +ORDER BY + c +---- +108672393952-01-22 00:00:00 +0000 +0000 +108672393952-01-22 00:00:00 +0000 +0000 + +query T +SELECT + '1971-03-18'::DATE + 300866802885581286 +---- +108672393952-01-22 00:00:00 +0000 +0000 diff --git a/pkg/util/timeutil/pgdate/field_extract.go b/pkg/util/timeutil/pgdate/field_extract.go index d2381209dc7a..f1db7fe2af3f 100644 --- a/pkg/util/timeutil/pgdate/field_extract.go +++ b/pkg/util/timeutil/pgdate/field_extract.go @@ -228,11 +228,11 @@ func (fe *fieldExtract) Extract(s string) error { // of which fields have already been set in order to keep picking // out field data. textMonth := !fe.Wants(fieldMonth) - for _, n := range numbers { + for i := range numbers { if fe.wanted == 0 { return inputErrorf("too many input fields") } - if err := fe.interpretNumber(n, textMonth); err != nil { + if err := fe.interpretNumber(numbers, i, textMonth); err != nil { return err } } @@ -248,7 +248,8 @@ func (fe *fieldExtract) Get(field field) (int, bool) { // interpretNumber applies pattern-matching rules to figure out which // field the next chunk of input should be applied to. -func (fe *fieldExtract) interpretNumber(chunk numberChunk, textMonth bool) error { +func (fe *fieldExtract) interpretNumber(numbers []numberChunk, idx int, textMonth bool) error { + chunk := numbers[idx] switch { case chunk.separator == '.': // Example: 04:04:04.913231+00:00, a fractional second. @@ -318,9 +319,16 @@ func (fe *fieldExtract) interpretNumber(chunk numberChunk, textMonth bool) error return fe.SetDayOfYear(chunk) case fe.Wants(fieldYear) && fe.Wants(fieldMonth) && fe.Wants(fieldDay): + var nextSep rune + if len(numbers) > idx+1 { + nextSep = numbers[idx+1].separator + } // Example: All date formats, we're starting from scratch. switch { - case chunk.magnitude >= 6 && chunk.separator != '-': + // We examine the next separator to decide if this is a + // concatenated date or a really long year. If it's a - or / + // then this is one part of a date instead of the whole date. + case chunk.magnitude >= 6 && chunk.separator != '-' && nextSep != '-' && nextSep != '/': // Example: "YYMMDD" // ^^^^^^ // Example: "YYYYMMDD" @@ -519,7 +527,7 @@ func (fe *fieldExtract) interpretNumber(chunk numberChunk, textMonth bool) error // timezone is in the middle of a timestamp. fe.has = fe.has.AddAll(tzFields) fe.wanted = fe.wanted.ClearAll(tzFields) - return fe.interpretNumber(chunk, textMonth) + return fe.interpretNumber(numbers, idx, textMonth) case !fe.Wants(fieldTZHour) && !fe.Wants(fieldTZMinute) && fe.Wants(fieldTZSecond): // Example: "