in sql_utils/public/interval_value.cc [574:733]
absl::StatusOr<IntervalValue> IntervalValue::ParseFromString(
absl::string_view input, functions::DateTimestampPart from,
functions::DateTimestampPart to) {
// Sign (empty, '-' or '+') for months and nano fields. There is no special
// treatment for sign of days, because days are standalone number and are
// matched and parsed by RE2 as part of ([-+]?\d+) group.
std::string sign_months;
std::string sign_nanos;
// All the datetime fields
int64_t years = 0;
int64_t months = 0;
int64_t days = 0;
int64_t hours = 0;
int64_t minutes = 0;
int64_t seconds = 0;
// Fractions of seconds
absl::string_view fraction_digits;
// Indication whether parsing succeeded.
bool parsed = false;
// Seconds are special, because they can have optional fractions
if (to == functions::SECOND && input.find('.') != input.npos) {
switch (from) {
case functions::YEAR:
parsed = RE2::FullMatch(input, *kREYearToSecondFractions, &sign_months,
&years, &months, &days, &sign_nanos, &hours,
&minutes, &seconds, &fraction_digits);
break;
case functions::MONTH:
parsed = RE2::FullMatch(input, *kREMonthToSecondFractions, &sign_months,
&months, &days, &sign_nanos, &hours, &minutes,
&seconds, &fraction_digits);
break;
case functions::DAY:
parsed =
RE2::FullMatch(input, *kREDayToSecondFractions, &days, &sign_nanos,
&hours, &minutes, &seconds, &fraction_digits);
break;
case functions::HOUR:
parsed = RE2::FullMatch(input, *kREHourToSecondFractions, &sign_nanos,
&hours, &minutes, &seconds, &fraction_digits);
break;
case functions::MINUTE:
parsed = RE2::FullMatch(input, *kREMinuteToSecondFractions, &sign_nanos,
&minutes, &seconds, &fraction_digits);
break;
default:
return MakeEvalError()
<< "Invalid interval datetime fields: "
<< functions::DateTimestampPart_Name(from) << " TO "
<< functions::DateTimestampPart_Name(to);
}
} else {
#define DATETIME_PARTS(from, to) (from << 16 | to)
switch (DATETIME_PARTS(from, to)) {
case DATETIME_PARTS(functions::YEAR, functions::MONTH):
parsed = RE2::FullMatch(input, *kREYearToMonth, &sign_months, &years,
&months);
break;
case DATETIME_PARTS(functions::YEAR, functions::DAY):
parsed = RE2::FullMatch(input, *kREYearToDay, &sign_months, &years,
&months, &days);
break;
case DATETIME_PARTS(functions::YEAR, functions::HOUR):
parsed = RE2::FullMatch(input, *kREYearToHour, &sign_months, &years,
&months, &days, &sign_nanos, &hours);
break;
case DATETIME_PARTS(functions::YEAR, functions::MINUTE):
parsed = RE2::FullMatch(input, *kREYearToMinute, &sign_months, &years,
&months, &days, &sign_nanos, &hours, &minutes);
break;
case DATETIME_PARTS(functions::YEAR, functions::SECOND):
parsed = RE2::FullMatch(input, *kREYearToSecond, &sign_months, &years,
&months, &days, &sign_nanos, &hours, &minutes,
&seconds);
break;
case DATETIME_PARTS(functions::MONTH, functions::DAY):
parsed =
RE2::FullMatch(input, *kREMonthToDay, &sign_months, &months, &days);
break;
case DATETIME_PARTS(functions::MONTH, functions::HOUR):
parsed = RE2::FullMatch(input, *kREMonthToHour, &sign_months, &months,
&days, &sign_nanos, &hours);
break;
case DATETIME_PARTS(functions::MONTH, functions::MINUTE):
parsed = RE2::FullMatch(input, *kREMonthToMinute, &sign_months, &months,
&days, &sign_nanos, &hours, &minutes);
break;
case DATETIME_PARTS(functions::MONTH, functions::SECOND):
parsed = RE2::FullMatch(input, *kREMonthToSecond, &sign_months, &months,
&days, &sign_nanos, &hours, &minutes, &seconds);
break;
case DATETIME_PARTS(functions::DAY, functions::HOUR):
parsed =
RE2::FullMatch(input, *kREDayToHour, &days, &sign_nanos, &hours);
break;
case DATETIME_PARTS(functions::DAY, functions::MINUTE):
parsed = RE2::FullMatch(input, *kREDayToMinute, &days, &sign_nanos,
&hours, &minutes);
break;
case DATETIME_PARTS(functions::DAY, functions::SECOND):
parsed = RE2::FullMatch(input, *kREDayToSecond, &days, &sign_nanos,
&hours, &minutes, &seconds);
break;
case DATETIME_PARTS(functions::HOUR, functions::MINUTE):
parsed = RE2::FullMatch(input, *kREHourToMinute, &sign_nanos, &hours,
&minutes);
break;
case DATETIME_PARTS(functions::HOUR, functions::SECOND):
parsed = RE2::FullMatch(input, *kREHourToSecond, &sign_nanos, &hours,
&minutes, &seconds);
break;
case DATETIME_PARTS(functions::MINUTE, functions::SECOND):
parsed = RE2::FullMatch(input, *kREMinuteToSecond, &sign_nanos,
&minutes, &seconds);
break;
default:
return MakeEvalError()
<< "Invalid interval datetime fields: "
<< functions::DateTimestampPart_Name(from) << " TO "
<< functions::DateTimestampPart_Name(to);
}
#undef DATETIME_PARTS
}
if (!parsed) {
return MakeIntervalParsingError(input);
}
absl::Status status;
int64_t years_as_months;
if (!functions::Multiply(IntervalValue::kMonthsInYear, years,
&years_as_months, &status)) {
return status;
}
if (!functions::Add(years_as_months, months, &months, &status)) {
return status;
}
bool negative_months = !sign_months.empty() && sign_months[0] == '-';
if (negative_months) {
months = -months;
}
// Result always fits into int128.
__int128 nanos = IntervalValue::kNanosInHour * hours +
IntervalValue::kNanosInMinute * minutes +
IntervalValue::kNanosInSecond * seconds;
if (!fraction_digits.empty()) {
SQL_ASSIGN_OR_RETURN(int64_t nano_fractions,
NanosFromFractionDigits(input, fraction_digits));
nanos += nano_fractions;
}
bool negative_nanos = !sign_nanos.empty() && sign_nanos[0] == '-';
if (negative_nanos) {
nanos = -nanos;
}
return IntervalValue::FromMonthsDaysNanos(months, days, nanos);
}