in sql_utils/public/interval_value.cc [436:523]
absl::StatusOr<IntervalValue> IntervalValue::ParseFromString(
absl::string_view input, functions::DateTimestampPart part) {
absl::Status status;
// SimpleAtoi ignores leading and trailing spaces, but we reject them.
if (input.empty() || std::isspace(input.front()) ||
std::isspace(input.back())) {
return MakeIntervalParsingError(input);
}
// Seconds are special, because they allow fractions
if (part == functions::SECOND && input.find('.') != input.npos) {
absl::string_view sign;
absl::string_view seconds_text;
absl::string_view digits;
// [+|-][s][.ddddddddd] - capture sign, seconds and digits of fractions.
if (!RE2::FullMatch(input, *kRESecond, &sign, &seconds_text, &digits)) {
return MakeIntervalParsingError(input);
}
int64_t seconds = 0;
if (!seconds_text.empty()) {
// This SimpleAtoi can fail if there were too many digits for seconds.
if (!absl::SimpleAtoi(seconds_text, &seconds)) {
return MakeIntervalParsingError(input);
}
}
SQL_RET_CHECK(!digits.empty());
SQL_ASSIGN_OR_RETURN(__int128 nano_fractions,
NanosFromFractionDigits(input, digits));
// Result always fits into int128
__int128 nanos = IntervalValue::kNanosInSecond * seconds + nano_fractions;
bool negative = !sign.empty() && sign[0] == '-';
if (negative) {
nanos = -nanos;
}
return IntervalValue::FromNanos(nanos);
}
int64_t value;
if (!absl::SimpleAtoi(input, &value)) {
return MakeIntervalParsingError(input);
}
switch (part) {
case functions::YEAR:
if (!functions::Multiply(IntervalValue::kMonthsInYear, value, &value,
&status)) {
return status;
}
return IntervalValue::FromMonths(value);
case functions::QUARTER:
if (!functions::Multiply(IntervalValue::kMonthsInQuarter, value, &value,
&status)) {
return status;
}
return IntervalValue::FromMonths(value);
case functions::MONTH:
return IntervalValue::FromMonths(value);
case functions::WEEK:
if (!functions::Multiply(IntervalValue::kDaysInWeek, value, &value,
&status)) {
return status;
}
return IntervalValue::FromDays(value);
case functions::DAY:
return IntervalValue::FromDays(value);
case functions::HOUR:
if (!functions::Multiply(IntervalValue::kMicrosInHour, value, &value,
&status)) {
return status;
}
return IntervalValue::FromMicros(value);
case functions::MINUTE:
if (!functions::Multiply(IntervalValue::kMicrosInMinute, value, &value,
&status)) {
return status;
}
return IntervalValue::FromMicros(value);
case functions::SECOND:
if (!functions::Multiply(IntervalValue::kMicrosInSecond, value, &value,
&status)) {
return status;
}
return IntervalValue::FromMicros(value);
default:
return MakeEvalError() << "Unsupported interval datetime field "
<< functions::DateTimestampPart_Name(part);
}
}