diff --git a/src/IO/ReadHelpers.cpp b/src/IO/ReadHelpers.cpp index 5fe0fda88cd..41dcd9fde6c 100644 --- a/src/IO/ReadHelpers.cpp +++ b/src/IO/ReadHelpers.cpp @@ -768,17 +768,6 @@ ReturnType readDateTextFallback(LocalDate & date, ReadBuffer & buf) return ReturnType(false); }; - auto ignore_delimiter = [&] - { - if (!buf.eof() && !isNumericASCII(*buf.position())) - { - ++buf.position(); - return true; - } - else - return false; - }; - auto append_digit = [&](auto & x) { if (!buf.eof() && isNumericASCII(*buf.position())) @@ -792,27 +781,44 @@ ReturnType readDateTextFallback(LocalDate & date, ReadBuffer & buf) }; UInt16 year = 0; + UInt8 month = 0; + UInt8 day = 0; + if (!append_digit(year) || !append_digit(year) // NOLINT || !append_digit(year) // NOLINT || !append_digit(year)) // NOLINT return error(); - if (!ignore_delimiter()) + if (buf.eof()) return error(); - UInt8 month = 0; - if (!append_digit(month)) - return error(); - append_digit(month); + if (isNumericASCII(*buf.position())) + { + /// YYYYMMDD + if (!append_digit(month) + || !append_digit(month) // NOLINT + || !append_digit(day) + || !append_digit(day)) // NOLINT + return error(); + } + else + { + ++buf.position(); - if (!ignore_delimiter()) - return error(); + if (!append_digit(month)) + return error(); + append_digit(month); - UInt8 day = 0; - if (!append_digit(day)) - return error(); - append_digit(day); + if (!buf.eof() && !isNumericASCII(*buf.position())) + ++buf.position(); + else + return error(); + + if (!append_digit(day)) + return error(); + append_digit(day); + } date = LocalDate(year, month, day); return ReturnType(true); diff --git a/src/IO/ReadHelpers.h b/src/IO/ReadHelpers.h index fda8c213ebf..81973bcd8a4 100644 --- a/src/IO/ReadHelpers.h +++ b/src/IO/ReadHelpers.h @@ -597,35 +597,45 @@ inline ReturnType readDateTextImpl(LocalDate & date, ReadBuffer & buf) /// YYYY-MM-D /// YYYY-M-DD /// YYYY-M-D + /// YYYYMMDD /// The delimiters can be arbitrary characters, like YYYY/MM!DD, but obviously not digits. UInt16 year = (pos[0] - '0') * 1000 + (pos[1] - '0') * 100 + (pos[2] - '0') * 10 + (pos[3] - '0'); + UInt8 month; + UInt8 day; pos += 5; if (isNumericASCII(pos[-1])) - return ReturnType(false); - - UInt8 month = pos[0] - '0'; - if (isNumericASCII(pos[1])) { - month = month * 10 + pos[1] - '0'; + /// YYYYMMDD + month = (pos[-1] - '0') * 10 + (pos[0] - '0'); + day = (pos[1] - '0') * 10 + (pos[2] - '0'); pos += 3; } else - pos += 2; - - if (isNumericASCII(pos[-1])) - return ReturnType(false); - - UInt8 day = pos[0] - '0'; - if (isNumericASCII(pos[1])) { - day = day * 10 + pos[1] - '0'; - pos += 2; + month = pos[0] - '0'; + if (isNumericASCII(pos[1])) + { + month = month * 10 + pos[1] - '0'; + pos += 3; + } + else + pos += 2; + + if (isNumericASCII(pos[-1])) + return ReturnType(false); + + day = pos[0] - '0'; + if (isNumericASCII(pos[1])) + { + day = day * 10 + pos[1] - '0'; + pos += 2; + } + else + pos += 1; } - else - pos += 1; buf.position() = pos; date = LocalDate(year, month, day); diff --git a/tests/queries/0_stateless/02112_parse_date_yyyymmdd.reference b/tests/queries/0_stateless/02112_parse_date_yyyymmdd.reference new file mode 100644 index 00000000000..dc49af313b7 --- /dev/null +++ b/tests/queries/0_stateless/02112_parse_date_yyyymmdd.reference @@ -0,0 +1 @@ +2021-02-03 2021-03-04 2021-04-05 diff --git a/tests/queries/0_stateless/02112_parse_date_yyyymmdd.sh b/tests/queries/0_stateless/02112_parse_date_yyyymmdd.sh new file mode 100755 index 00000000000..0c18697eb06 --- /dev/null +++ b/tests/queries/0_stateless/02112_parse_date_yyyymmdd.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CURDIR"/../shell_config.sh + +echo '20210203,2021-03-04,20210405' | $CLICKHOUSE_LOCAL --input-format CSV --structure 'a Date, b Date, c Date' --query 'SELECT * FROM table'