Skip to content

Commit

Permalink
Merge pull request #9 from AikidoSec/string-escape-constant
Browse files Browse the repository at this point in the history
Only support string escape constant for Postgres, Redshift and generic dialect
  • Loading branch information
willem-delbare authored Jan 24, 2025
2 parents 1fab7b2 + f54d2f9 commit e003b3e
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/dialect/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,8 @@ impl Dialect for GenericDialect {
fn supports_nested_comments(&self) -> bool {
true
}

fn supports_string_escape_constant(&self) -> bool {
true
}
}
7 changes: 7 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,13 @@ pub trait Dialect: Debug + Any {
fn supports_nested_comments(&self) -> bool {
false
}

/// Returns true if this dialect supports the E'...' syntax for string literals
///
/// Postgres: <https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE>
fn supports_string_escape_constant(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ impl Dialect for PostgreSqlDialect {
fn supports_nested_comments(&self) -> bool {
true
}

fn supports_string_escape_constant(&self) -> bool {
true
}
}

pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/redshift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,8 @@ impl Dialect for RedshiftSqlDialect {
fn supports_connect_by(&self) -> bool {
true
}

fn supports_string_escape_constant(&self) -> bool {
true
}
}
6 changes: 5 additions & 1 deletion src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,17 @@ impl TestedDialects {

/// Check that the tokenizer returns the expected tokens for the given SQL.
pub fn tokenizes_to(&self, sql: &str, expected: Vec<Token>) {
if self.dialects.is_empty() {
panic!("No dialects to test");
}

self.dialects.iter().for_each(|dialect| {
let mut tokenizer = Tokenizer::new(&**dialect, sql);
if let Some(options) = &self.options {
tokenizer = tokenizer.with_unescape(options.unescape);
}
let tokens = tokenizer.tokenize().unwrap();
assert_eq!(expected, tokens);
assert_eq!(expected, tokens, "Tokenized differently for {:?}", dialect);
});
}
}
Expand Down
46 changes: 45 additions & 1 deletion src/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ impl<'a> Tokenizer<'a> {
}
}
// PostgreSQL accepts "escape" string constants, which are an extension to the SQL standard.
x @ 'e' | x @ 'E' => {
x @ 'e' | x @ 'E' if self.dialect.supports_string_escape_constant() => {
let starting_loc = chars.location();
chars.next(); // consume, to check the next char
match chars.peek() {
Expand Down Expand Up @@ -3244,4 +3244,48 @@ mod tests {
],
);
}

#[test]
fn test_string_escape_constant_not_supported() {
all_dialects_where(|dialect| !dialect.supports_string_escape_constant()).tokenizes_to(
"select e'...'",
vec![
Token::make_keyword("select"),
Token::Whitespace(Whitespace::Space),
Token::make_word("e", None),
Token::SingleQuotedString("...".to_string()),
],
);

all_dialects_where(|dialect| !dialect.supports_string_escape_constant()).tokenizes_to(
"select E'...'",
vec![
Token::make_keyword("select"),
Token::Whitespace(Whitespace::Space),
Token::make_word("E", None),
Token::SingleQuotedString("...".to_string()),
],
);
}

#[test]
fn test_string_escape_constant_supported() {
all_dialects_where(|dialect| dialect.supports_string_escape_constant()).tokenizes_to(
"select e'\\''",
vec![
Token::make_keyword("select"),
Token::Whitespace(Whitespace::Space),
Token::EscapedStringLiteral("'".to_string()),
],
);

all_dialects_where(|dialect| dialect.supports_string_escape_constant()).tokenizes_to(
"select E'\\''",
vec![
Token::make_keyword("select"),
Token::Whitespace(Whitespace::Space),
Token::EscapedStringLiteral("'".to_string()),
],
);
}
}

0 comments on commit e003b3e

Please sign in to comment.