absl::StatusOr GetNextDateTimeFormatElement()

in sql_utils/public/functions/cast_date_time.cc [1615:1699]


absl::StatusOr<DateTimeFormatElement> GetNextDateTimeFormatElement(
    absl::string_view format_str, absl::string_view upper_format_str) {
  DateTimeFormatElement format_element;
  int matched_len;
  const FormatElementTypeTrie& format_element_type_trie =
      GetFormatElementTypeTrie();
  const FormatElementType& type =
      format_element_type_trie.GetDataForMaximalPrefix(
          upper_format_str, &matched_len, /*is_terminator = */ nullptr);
  if (type == kFormatElementTypeNullValue) {
    return MakeEvalError() << "Cannot find matched format element";
  }

  format_element.type = type;
  format_element.category = GetFormatElementCategoryFromType(type);

  if (format_element.category != FormatElementCategory::kLiteral) {
    SQL_ASSIGN_OR_RETURN(
        format_element.format_casing_type,
        GetFormatCasingTypeOfNonLiteralElements(
            format_str.substr(0, matched_len), format_element.category));
    format_element.len_in_format_str = matched_len;
    if (format_element.type == FormatElementType::kFFN &&
        !absl::SimpleAtoi(format_str.substr(2, matched_len - 2),
                          &format_element.subsecond_digit_count)) {
      return MakeEvalError() << "Failed to parse format element of FFN type";
    }
    return format_element;
  }

  // For literal format elements, we preserve casing of output letters since
  // they are originally from user input format string.
  format_element.format_casing_type = FormatCasingType::kPreserveCase;
  if (format_element.type == FormatElementType::kSimpleLiteral) {
    format_element.len_in_format_str = matched_len;
    format_element.literal_value = format_str.substr(0, matched_len);
    return format_element;
  }

  if (format_element.type == FormatElementType::kWhitespace) {
    // If the matched type is "kWhitespace", we search for the end of sequence
    // of consecutive ' ' (ASCII 32) characters.
    while (matched_len < format_str.length() &&
           format_str[matched_len] == ' ') {
      matched_len++;
    }
    format_element.len_in_format_str = matched_len;
    return format_element;
  }

  SQL_RET_CHECK(format_element.type == FormatElementType::kDoubleQuotedLiteral);
  // If the matched type is "kDoubleQuotedLiteral", we search for the end
  // manually and do the unescaping in this process.
  format_element.literal_value = "";
  size_t ind_to_check = 1;
  bool is_escaped = false;
  bool stop_search = false;

  while (ind_to_check < format_str.length() && !stop_search) {
    // Includes the char at position <ind_to_check>.
    matched_len++;
    char char_to_check = format_str[ind_to_check];
    ind_to_check++;
    if (is_escaped) {
      if (char_to_check == '\\' || char_to_check == '\"') {
        is_escaped = false;
      } else {
        return MakeEvalError() << "Unsupported escape sequence \\"
                               << char_to_check << " in text";
      }
    } else if (char_to_check == '\\') {
      is_escaped = true;
      continue;
    } else if (char_to_check == '\"') {
      stop_search = true;
      break;
    }
    format_element.literal_value.push_back(char_to_check);
  }
  if (!stop_search) {
    return MakeEvalError() << "Cannot find matching \" for quoted literal";
  }
  format_element.len_in_format_str = matched_len;
  return format_element;
}