absl::StatusOr IntervalValue::ParseFromString()

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);
  }
}