absl::StatusOr Parse()

in sql_utils/public/interval_value.cc [819:965]


  absl::StatusOr<IntervalValue> Parse(absl::string_view input) {
    input_ = input;
    char c = GetChar();
    if (c != 'P') {
      return MakeIntervalParsingError(input)
             << ": Interval must start with 'P'";
    }
    if (input_.empty()) {
      return MakeIntervalParsingError(input)
             << ": At least one datetime part must be defined in the interval";
    }
    absl::Status status;

    // When true - parsing time part (after T), when false - parsing date part.
    bool in_time_part = false;
    int64_t years = 0;
    int64_t months = 0;
    int64_t weeks = 0;
    int64_t days = 0;
    int64_t hours = 0;
    int64_t minutes = 0;
    int64_t seconds = 0;
    int64_t nano_fractions = 0;
    for (;;) {
      int64_t sign = false;
      c = PeekChar();
      if (c == kEof) {
        break;
      }
      if (!std::isdigit(c)) {
        GetChar();
        if (c == '-') {
          // Proceed to parse the number and make it negative later
          sign = true;
        } else if (c == 'T') {
          // Switching from date to time part
          if (in_time_part) {
            return MakeIntervalParsingError(input)
                   << ": Unexpected duplicate time separator 'T'";
          }
          in_time_part = true;
          continue;
        } else {
          return MakeIntervalParsingError(input)
                 << ": Unexpected " << PrintChar(c);
        }
      }
      // We now expect to see positive number (possibly with fractional digits)
      // followed by datetime part letter.
      SQL_RETURN_IF_ERROR(ParseNumber());
      int64_t number;
      if (!absl::SimpleAtoi(digits_, &number)) {
        return MakeIntervalParsingError(input)
               << ": Cannot convert '" << digits_ << "' to integer";
      }
      // number couldn't have been negative, so no worries about underflow
      // of int64_t::min
      if (sign) number = -number;
      c = GetChar();
      if (!in_time_part) {
        switch (c) {
          case 'Y':
            if (!functions::Add(years, number, &years, &status)) {
              return status;
            }
            break;
          case 'M':
            if (!functions::Add(months, number, &months, &status)) {
              return status;
            }
            break;
          case 'W':
            if (!functions::Add(weeks, number, &weeks, &status)) {
              return status;
            }
            break;
          case 'D':
            if (!functions::Add(days, number, &days, &status)) {
              return status;
            }
            break;
          default:
            return MakeIntervalParsingError(input)
                   << ": Unexpected " << PrintChar(c)
                   << " in the date portion of interval";
        }
      } else {
        switch (c) {
          case 'H':
            if (!functions::Add(hours, number, &hours, &status)) {
              return status;
            }
            break;
          case 'M':
            if (!functions::Add(minutes, number, &minutes, &status)) {
              return status;
            }
            break;
          case 'S':
            if (!functions::Add(seconds, number, &seconds, &status)) {
              return status;
            }
            if (!decimal_point_.empty()) {
              SQL_ASSIGN_OR_RETURN(
                  number, NanosFromFractionDigits(input_, decimal_digits_));
              if (sign) number = -number;
              nano_fractions += number;
            }
            break;
          default:
            return MakeIntervalParsingError(input)
                   << ": Unexpected " << PrintChar(c)
                   << " in the time portion of interval";
        }
      }
      if (!decimal_point_.empty() && c != 'S') {
        return MakeIntervalParsingError(input)
               << ": Fractional values are only allowed for "
                  "seconds part 'S', but were used for "
               << PrintChar(c);
      }
    }

    int64_t year_months;
    if (!functions::Multiply(IntervalValue::kMonthsInYear, years, &year_months,
                             &status)) {
      return status;
    }
    if (!functions::Add(months, year_months, &months, &status)) {
      return status;
    }

    int64_t week_days;
    if (!functions::Multiply(IntervalValue::kDaysInWeek, weeks, &week_days,
                             &status)) {
      return status;
    }
    if (!functions::Add(days, week_days, &days, &status)) {
      return status;
    }

    // Int128 math cannot overflow
    __int128 nanos = IntervalValue::kNanosInHour * hours +
                     IntervalValue::kNanosInMinute * minutes +
                     IntervalValue::kNanosInSecond * seconds + nano_fractions;
    return IntervalValue::FromMonthsDaysNanos(months, days, nanos);
  }