Add ODBC escape syntax support for time expressions (#1953)

This commit is contained in:
etgarperets 2025-07-29 13:37:04 +03:00 committed by GitHub
parent 97a5b61a73
commit bde269b56f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 259 additions and 110 deletions

View file

@ -1543,10 +1543,11 @@ impl<'a> Parser<'a> {
// an unary negation `NOT ('a' LIKE 'b')`. To solve this, we don't accept the
// `type 'string'` syntax for the custom data types at all.
DataType::Custom(..) => parser_err!("dummy", loc),
data_type => Ok(Expr::TypedString {
data_type => Ok(Expr::TypedString(TypedString {
data_type,
value: parser.parse_value()?,
}),
uses_odbc_syntax: false,
})),
}
})?;
@ -1732,10 +1733,11 @@ impl<'a> Parser<'a> {
}
fn parse_geometric_type(&mut self, kind: GeometricTypeKind) -> Result<Expr, ParserError> {
Ok(Expr::TypedString {
Ok(Expr::TypedString(TypedString {
data_type: DataType::GeometricType(kind),
value: self.parse_value()?,
})
uses_odbc_syntax: false,
}))
}
/// Try to parse an [Expr::CompoundFieldAccess] like `a.b.c` or `a.b[1].c`.
@ -2032,6 +2034,50 @@ impl<'a> Parser<'a> {
})
}
/// Tries to parse the body of an [ODBC escaping sequence]
/// i.e. without the enclosing braces
/// Currently implemented:
/// Scalar Function Calls
/// Date, Time, and Timestamp Literals
/// See <https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/escape-sequences-in-odbc?view=sql-server-2017>
fn maybe_parse_odbc_body(&mut self) -> Result<Option<Expr>, ParserError> {
// Attempt 1: Try to parse it as a function.
if let Some(expr) = self.maybe_parse_odbc_fn_body()? {
return Ok(Some(expr));
}
// Attempt 2: Try to parse it as a Date, Time or Timestamp Literal
self.maybe_parse_odbc_body_datetime()
}
/// Tries to parse the body of an [ODBC Date, Time, and Timestamp Literals] call.
///
/// ```sql
/// {d '2025-07-17'}
/// {t '14:12:01'}
/// {ts '2025-07-17 14:12:01'}
/// ```
///
/// [ODBC Date, Time, and Timestamp Literals]:
/// https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals?view=sql-server-2017
fn maybe_parse_odbc_body_datetime(&mut self) -> Result<Option<Expr>, ParserError> {
self.maybe_parse(|p| {
let token = p.next_token().clone();
let word_string = token.token.to_string();
let data_type = match word_string.as_str() {
"t" => DataType::Time(None, TimezoneInfo::None),
"d" => DataType::Date,
"ts" => DataType::Timestamp(None, TimezoneInfo::None),
_ => return p.expected("ODBC datetime keyword (t, d, or ts)", token),
};
let value = p.parse_value()?;
Ok(Expr::TypedString(TypedString {
data_type,
value,
uses_odbc_syntax: true,
}))
})
}
/// Tries to parse the body of an [ODBC function] call.
/// i.e. without the enclosing braces
///
@ -2786,7 +2832,7 @@ impl<'a> Parser<'a> {
fn parse_lbrace_expr(&mut self) -> Result<Expr, ParserError> {
let token = self.expect_token(&Token::LBrace)?;
if let Some(fn_expr) = self.maybe_parse_odbc_fn_body()? {
if let Some(fn_expr) = self.maybe_parse_odbc_body()? {
self.expect_token(&Token::RBrace)?;
return Ok(fn_expr);
}