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