in sql_utils/public/functions/parse_date_time.cc [1649:1710]
static absl::Status ValidateParseFormat(absl::string_view format_string,
absl::string_view target_type_name,
const char* invalid_elements) {
const char* cur = format_string.data();
const char* end = cur + format_string.size();
while (cur != end) {
while (cur != end && *cur != '%') ++cur;
// Span the sequential percent signs.
const char* percent = cur;
while (cur != end && *cur == '%') ++cur;
// Loop unless we have an unescaped percent.
if (cur == end || (cur - percent) % 2 == 0) {
continue;
}
// Returns error if the format is any of the <invalid_elements>
if (strchr(invalid_elements, *cur)) {
return MakeEvalError() << "Invalid format: %" << *cur
<< " is not allowed for the " << target_type_name
<< " type.";
}
const char* prev = cur;
if ((*cur != 'E' && *cur != 'O') || ++cur == end) {
continue;
}
if (*prev == 'E') {
// Check %E extensions.
if (strchr(invalid_elements, *cur) ||
// If %S (second) is invalid, then %E#S and %E*S should also be
// invalid.
(strchr(invalid_elements, 'S') &&
((*cur == '*' || std::isdigit(*cur)) && ++cur != end &&
*cur == 'S')) ||
// If %Y (year) is invalid, then %E4Y should also be invalid.
(strchr(invalid_elements, 'Y') && *cur == '4' && ++cur != end &&
*cur == 'Y')) {
std::string element;
while (prev != cur) {
element.push_back(*prev);
++prev;
}
element.push_back(*cur);
return MakeEvalError() << "Invalid format: %" << element
<< " is not allowed for the " << target_type_name
<< " type.";
}
} else if (*prev == 'O') {
// Check %O extensions.
if (strchr(invalid_elements, *cur)) {
return MakeEvalError() << "Invalid format: %O" << *cur
<< " is not allowed for the " << target_type_name
<< " type.";
}
}
}
return absl::OkStatus();
}