completely remove usage of enum variants

This commit is contained in:
Nikita Sivukhin
2025-09-25 18:27:14 +04:00
parent 9f2f8438e0
commit f3f9219795
8 changed files with 64 additions and 58 deletions

View File

@@ -891,6 +891,9 @@ impl Name {
pub fn exact(s: String) -> Self {
Self::Ident(s)
}
pub fn from_bytes(s: &[u8]) -> Self {
Self::new(unsafe { std::str::from_utf8_unchecked(s) }.to_owned())
}
pub fn new(s: impl AsRef<str>) -> Self {
let s = s.as_ref();
let bytes = s.as_bytes();
@@ -911,13 +914,27 @@ impl Name {
}
}
/// Checks if a name represents a double-quoted string that should get fallback behavior
pub fn is_double_quoted(&self) -> bool {
pub fn as_literal(&self) -> &str {
match self {
Name::Ident(s) | Name::Quoted(s) => s.as_str(),
}
}
/// Checks if a name represents a quoted string that should get fallback behavior
/// Need to detect legacy conversion of double quoted keywords to string literals
/// (see https://sqlite.org/lang_keywords.html)
///
/// Also, used to detect string literals in PRAGMA cases
pub fn quoted_with(&self, quote: char) -> bool {
if let Self::Quoted(ident) = self {
return ident.starts_with("\"");
return ident.starts_with(quote);
}
false
}
pub fn quoted(&self) -> bool {
matches!(self, Self::Quoted(..))
}
}
/// Qualified name

View File

@@ -605,12 +605,7 @@ impl<'a> Parser<'a> {
fn parse_nm(&mut self) -> Result<Name> {
let tok = eat_expect!(self, TK_ID, TK_STRING, TK_INDEXED, TK_JOIN_KW);
let first_char = tok.value[0]; // no need to check empty
match first_char {
b'[' | b'\'' | b'`' | b'"' => Ok(Name::Quoted(from_bytes(tok.value))),
_ => Ok(Name::exact(from_bytes(tok.value))),
}
Ok(Name::from_bytes(tok.value))
}
fn parse_transopt(&mut self) -> Result<Option<Name>> {
@@ -1465,7 +1460,10 @@ impl<'a> Parser<'a> {
}
_ => {
let can_be_lit_str = tok.token_type == Some(TK_STRING);
let name = self.parse_nm()?;
// can be either Literal::String or Name - so we parse raw value early and decide later
let tok = eat_expect!(self, TK_ID, TK_STRING, TK_INDEXED, TK_JOIN_KW);
let name = tok.value;
let second_name = if let Some(tok) = self.peek()? {
if tok.token_type == Some(TK_DOT) {
@@ -1487,7 +1485,7 @@ impl<'a> Parser<'a> {
eat_assert!(self, TK_STAR);
eat_expect!(self, TK_RP);
return Ok(Box::new(Expr::FunctionCallStar {
name,
name: Name::from_bytes(name),
filter_over: self.parse_filter_over()?,
}));
}
@@ -1498,7 +1496,7 @@ impl<'a> Parser<'a> {
eat_expect!(self, TK_RP);
let filter_over = self.parse_filter_over()?;
return Ok(Box::new(Expr::FunctionCall {
name,
name: Name::from_bytes(name),
distinctness: distinct,
args: exprs,
order_by,
@@ -1528,34 +1526,29 @@ impl<'a> Parser<'a> {
if let Some(second_name) = second_name {
if let Some(third_name) = third_name {
Ok(Box::new(Expr::DoublyQualified(
name,
Name::from_bytes(name),
second_name,
third_name,
)))
} else {
Ok(Box::new(Expr::Qualified(name, second_name)))
Ok(Box::new(Expr::Qualified(
Name::from_bytes(name),
second_name,
)))
}
} else if can_be_lit_str {
Ok(Box::new(Expr::Literal(match name {
Name::Quoted(s) => Literal::String(s),
Name::Ident(s) => Literal::String(s),
})))
Ok(Box::new(Expr::Literal(Literal::String(from_bytes(name)))))
} else {
match name {
Name::Ident(s) => {
let s_bytes = s.as_bytes();
match_ignore_ascii_case!(match s_bytes {
b"true" => {
Ok(Box::new(Expr::Literal(Literal::Numeric("1".into()))))
}
b"false" => {
Ok(Box::new(Expr::Literal(Literal::Numeric("0".into()))))
}
_ => Ok(Box::new(Expr::Id(Name::exact(s)))),
})
match_ignore_ascii_case!(match name {
b"true" => {
Ok(Box::new(Expr::Literal(Literal::Numeric("1".into()))))
}
_ => Ok(Box::new(Expr::Id(name))),
}
b"false" => {
Ok(Box::new(Expr::Literal(Literal::Numeric("0".into()))))
}
_ => Ok(Box::new(Expr::Id(Name::from_bytes(name)))),
})
}
}
}
@@ -1919,11 +1912,7 @@ impl<'a> Parser<'a> {
}
let tok = eat_expect!(self, TK_ID, TK_STRING);
let first_char = tok.value[0]; // no need to check empty
match first_char {
b'[' | b'\'' | b'`' | b'"' => Ok(Some(Name::Quoted(from_bytes(tok.value)))),
_ => Ok(Some(Name::exact(from_bytes(tok.value)))),
}
Ok(Some(Name::from_bytes(tok.value)))
}
fn parse_sort_order(&mut self) -> Result<Option<SortOrder>> {
@@ -4138,7 +4127,7 @@ mod tests {
b"BEGIN EXCLUSIVE TRANSACTION 'my_transaction'".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Exclusive),
name: Some(Name::Quoted("'my_transaction'".to_string())),
name: Some(Name::new("'my_transaction'".to_string())),
})],
),
(
@@ -4159,7 +4148,7 @@ mod tests {
b"BEGIN CONCURRENT TRANSACTION 'my_transaction'".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Concurrent),
name: Some(Name::Quoted("'my_transaction'".to_string())),
name: Some(Name::new("'my_transaction'".to_string())),
})],
),
(
@@ -4254,7 +4243,7 @@ mod tests {
(
b"SAVEPOINT 'my_savepoint'".as_slice(),
vec![Cmd::Stmt(Stmt::Savepoint {
name: Name::Quoted("'my_savepoint'".to_string()),
name: Name::new("'my_savepoint'".to_string()),
})],
),
// release
@@ -4273,7 +4262,7 @@ mod tests {
(
b"RELEASE SAVEPOINT 'my_savepoint'".as_slice(),
vec![Cmd::Stmt(Stmt::Release {
name: Name::Quoted("'my_savepoint'".to_string()),
name: Name::new("'my_savepoint'".to_string()),
})],
),
(
@@ -11485,13 +11474,13 @@ mod tests {
if_not_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Quoted("\"settings\"".to_owned()),
name: Name::new("\"settings\"".to_owned()),
alias: None,
},
body: CreateTableBody::ColumnsAndConstraints{
columns: vec![
ColumnDefinition {
col_name: Name::Quoted("\"enabled\"".to_owned()),
col_name: Name::new("\"enabled\"".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,