Skip to content

Commit

Permalink
MySQL datetime guardrail (#428)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tang8330 authored Jul 3, 2024
1 parent c5a81ec commit f2af92b
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
33 changes: 29 additions & 4 deletions lib/mysql/schema/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"time"
)

Expand Down Expand Up @@ -82,13 +84,12 @@ func ConvertValue(value any, colType DataType) (any, error) {
return nil, fmt.Errorf("expected []byte got %T for value: %v", value, value)
}

if string(bytesValue) == "0000-00-00 00:00:00" {
// MySQL supports '0000-00-00 00:00:00' for datetime columns.
// We are returning `nil` here because this will fail most Time parsers.
stringValue := string(bytesValue)
if hasNonStrictModeInvalidDate(stringValue) {
return nil, nil
}

timeValue, err := time.Parse(DateTimeFormat, string(bytesValue))
timeValue, err := time.Parse(DateTimeFormat, stringValue)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -184,3 +185,27 @@ func ConvertValues(values []any, cols []Column) error {
}
return nil
}

// hasNonStrictModeInvalidDate - if strict mode is not enabled, we can end up having invalid datetimes
func hasNonStrictModeInvalidDate(d string) bool {
if len(d) < 10 {
return false
}

parts := strings.Split(d[:10], "-")
if len(parts) != 3 {
return false
}

// Year, month, date cannot be non-zero
for _, part := range parts {
value, err := strconv.Atoi(part)
if err != nil {
return false
}
if value == 0 {
return true
}
}
return false
}
13 changes: 13 additions & 0 deletions lib/mysql/schema/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,16 @@ func TestConvertValues(t *testing.T) {
assert.Equal(t, []any{int64(1234), "hello world", true}, values)
}
}

func TestHasNonStrictModeInvalidDate(t *testing.T) {
assert.False(t, hasNonStrictModeInvalidDate(""))
assert.False(t, hasNonStrictModeInvalidDate("hello world"))
assert.False(t, hasNonStrictModeInvalidDate("2021-01-02"))
assert.False(t, hasNonStrictModeInvalidDate("2021--01-02"))
assert.False(t, hasNonStrictModeInvalidDate("2021-01-02 03:04:05"))

assert.True(t, hasNonStrictModeInvalidDate("2009-00-00"))
assert.True(t, hasNonStrictModeInvalidDate("0000-00-00"))
assert.True(t, hasNonStrictModeInvalidDate("0000-00-00 00:00:00"))
assert.True(t, hasNonStrictModeInvalidDate("2009-00-00 00:00:00"))
}

0 comments on commit f2af92b

Please sign in to comment.