Skip to content

Commit

Permalink
Merge pull request #52 from gwenn/dequote
Browse files Browse the repository at this point in the history
Dequote column name
  • Loading branch information
gwenn authored Mar 17, 2024
2 parents 6e5fd27 + 603bc9d commit 7edcf6b
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 5 deletions.
8 changes: 8 additions & 0 deletions src/lexer/sql/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ fn duplicate_column() {
b"CREATE TABLE t (x TEXT, x TEXT)",
"duplicate column name: x",
);
expect_parser_err_msg(
b"CREATE TABLE t (x TEXT, \"x\" TEXT)",
"duplicate column name: x",
);
expect_parser_err_msg(
b"CREATE TABLE t (x TEXT, `x` TEXT)",
"duplicate column name: x",
);
}

#[test]
Expand Down
54 changes: 54 additions & 0 deletions src/parser/ast/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2035,3 +2035,57 @@ fn double_quote<S: TokenStream>(name: &str, s: &mut S) -> Result<(), S::Error> {
f.write_char('"')*/
s.append(TK_ID, Some(name))
}

/// Convert an SQL-style quoted string into a normal string by removing
/// the quote characters.
pub fn dequote(n: Name) -> Result<Name, ParserError> {
let s = n.0.as_str();
if s.is_empty() {
return Ok(n);
}
let mut quote = s.chars().nth(0).unwrap();
if quote != '"' && quote != '`' && quote != '\'' && quote != '[' {
return Ok(n);
} else if quote == '[' {
quote = ']';
}
debug_assert!(s.len() > 1);
debug_assert!(s.ends_with(quote));
let sub = &s[1..s.len() - 1];
let mut z = String::with_capacity(sub.len());
let mut escaped = false;
for c in sub.chars() {
if escaped {
if c != quote {
return Err(custom_err!("Malformed string literal: {}", s));
}
escaped = false;
} else if c == quote {
escaped = true;
continue;
}
z.push(c);
}
Ok(Name(Uncased::from_owned(z)))
}

#[cfg(test)]
mod test {
use super::{dequote, Name, ParserError};
use uncased::Uncased;

#[test]
fn test_dequote() -> Result<(), ParserError> {
assert_eq!(dequote(name("x"))?, name("x"));
assert_eq!(dequote(name("`x`"))?, name("x"));
assert_eq!(dequote(name("`x``y`"))?, name("x`y"));
assert_eq!(dequote(name(r#""x""#))?, name("x"));
assert_eq!(dequote(name(r#""x""y""#))?, name("x\"y"));
assert_eq!(dequote(name("[x]"))?, name("x"));
Ok(())
}

fn name(s: &'static str) -> Name {
Name(Uncased::from_borrowed(s))
}
}
9 changes: 5 additions & 4 deletions src/parser/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod fmt;
use std::num::ParseIntError;
use std::str::FromStr;

use fmt::{ToTokens, TokenStream};
use fmt::{dequote, ToTokens, TokenStream};
use indexmap::{IndexMap, IndexSet};
use uncased::Uncased;

Expand Down Expand Up @@ -1116,9 +1116,10 @@ impl ColumnDefinition {
columns: &mut IndexMap<Name, ColumnDefinition>,
mut cd: ColumnDefinition,
) -> Result<(), ParserError> {
if columns.contains_key(&cd.col_name) {
let col_name = dequote(cd.col_name.clone())?;
if columns.contains_key(&col_name) {
// TODO unquote
return Err(custom_err!("duplicate column name: {}", cd.col_name));
return Err(custom_err!("duplicate column name: {}", col_name));
}
// https://github.com/sqlite/sqlite/blob/e452bf40a14aca57fd9047b330dff282f3e4bbcc/src/build.c#L1511-L1514
if let Some(ref mut col_type) = cd.col_type {
Expand Down Expand Up @@ -1147,7 +1148,7 @@ impl ColumnDefinition {
col_type.name = new_type.join(" ");
}
}
columns.insert(cd.col_name.clone(), cd);
columns.insert(col_name, cd);
Ok(())
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/parser/parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ columnlist(A) ::= columnlist(A) COMMA columnname(X) carglist(Y). {
}
columnlist(A) ::= columnname(X) carglist(Y). {
let col = X;
let cd = ColumnDefinition{ col_name: col.0, col_type: col.1, constraints: Y };
let mut map = IndexMap::new();
map.insert(col.0.clone(), ColumnDefinition{ col_name: col.0, col_type: col.1, constraints: Y });
ColumnDefinition::add_column(&mut map, cd)?;
A = map;
}
%type columnname {(Name, Option<Type>)}
Expand Down

0 comments on commit 7edcf6b

Please sign in to comment.