in sql_utils/public/functions/cast_date_time.cc [1231:1314]
absl::Status ValidateDateTimeFormatElements(
const std::vector<DateTimeFormatElement>& format_elements,
const std::vector<FormatElementCategory>& invalid_categories,
absl::string_view output_type_name) {
CategoryToElementsMap category_to_elements_map;
TypeToElementMap type_to_element_map;
for (const DateTimeFormatElement& format_element : format_elements) {
if (!IsSupportedForParsing(format_element)) {
return MakeEvalError() << "Format element " << format_element.ToString()
<< " is not supported for parsing";
}
// We store at most 2 elements inside this map, since this is enough to
// print in error message when duplicate checks fail for a category.
if (category_to_elements_map[format_element.category].size() < 2) {
category_to_elements_map[format_element.category].push_back(
&format_element);
}
if (type_to_element_map.contains(format_element.type)) {
// We do not allow that more than one non-literal format element of the
// same type exist at the same time. For example, the format string
// "MiYYmI" is invalid since two format elements of "kMI" type
// (appearing as "Mi" and "MI") exist in it.
if (format_element.category != FormatElementCategory::kLiteral) {
return MakeEvalError() << absl::Substitute(
"Format element $0 appears more than once in the "
"format string",
format_element.ToString());
}
} else {
type_to_element_map[format_element.type] = &format_element;
}
}
// Checks invalid format element categories for the output type.
for (const FormatElementCategory& invalid_category : invalid_categories) {
SQL_RETURN_IF_ERROR(CheckCategoryNotExist(
invalid_category, category_to_elements_map, output_type_name));
}
// Checks categories which do not allow duplications.
const std::vector<FormatElementCategory> categories_to_check_duplicate = {
FormatElementCategory::kMeridianIndicator,
FormatElementCategory::kYear,
FormatElementCategory::kMonth,
FormatElementCategory::kDay,
FormatElementCategory::kHour,
FormatElementCategory::kMinute};
for (FormatElementCategory category : categories_to_check_duplicate) {
SQL_RETURN_IF_ERROR(CheckForDuplicateElementsInCategory(
category, category_to_elements_map));
}
// Checks mutually exclusive format elements/types.
// The Check between "kHH24" type and "kHH"/"kHH12" types is included in
// duplicate check for "kHour" category.
SQL_RETURN_IF_ERROR(CheckForMutuallyExclusiveElements(
FormatElementType::kHH24, FormatElementCategory::kMeridianIndicator,
type_to_element_map, category_to_elements_map));
// A Format element in "kMeridianIndicator" category must exist when a format
// element of "kHH" or "kHH12" is present. Also, if we have a format element
// in "kMeridianIndicator" category, a format element of "kHH" or "kHH12" type
// must exist.
SQL_RETURN_IF_ERROR(
CheckForCoexistance({FormatElementType::kHH, FormatElementType::kHH12},
FormatElementCategory::kMeridianIndicator,
type_to_element_map, category_to_elements_map));
// Format elements of "kSSSSS" type contain Hour, Minute and Second info,
// therefore elements in "kHour" (along with "kMeridianIndicator") and
// "kMinute" categories and elements of "kSS" type are disallowed.
SQL_RETURN_IF_ERROR(CheckForMutuallyExclusiveElements(
FormatElementType::kSSSSS, FormatElementCategory::kHour,
type_to_element_map, category_to_elements_map));
SQL_RETURN_IF_ERROR(CheckForMutuallyExclusiveElements(
FormatElementType::kSSSSS, FormatElementCategory::kMinute,
type_to_element_map, category_to_elements_map));
SQL_RETURN_IF_ERROR(CheckForMutuallyExclusiveElements(
FormatElementType::kSSSSS, FormatElementType::kSS, type_to_element_map));
return absl::OkStatus();
}