Skip to content

Commit e003b3e

Browse files
Merge pull request #9 from AikidoSec/string-escape-constant
Only support string escape constant for Postgres, Redshift and generic dialect
2 parents 1fab7b2 + f54d2f9 commit e003b3e

File tree

6 files changed

+69
-2
lines changed

6 files changed

+69
-2
lines changed

src/dialect/generic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,8 @@ impl Dialect for GenericDialect {
111111
fn supports_nested_comments(&self) -> bool {
112112
true
113113
}
114+
115+
fn supports_string_escape_constant(&self) -> bool {
116+
true
117+
}
114118
}

src/dialect/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,13 @@ pub trait Dialect: Debug + Any {
573573
fn supports_nested_comments(&self) -> bool {
574574
false
575575
}
576+
577+
/// Returns true if this dialect supports the E'...' syntax for string literals
578+
///
579+
/// Postgres: <https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE>
580+
fn supports_string_escape_constant(&self) -> bool {
581+
false
582+
}
576583
}
577584

578585
/// This represents the operators for which precedence must be defined

src/dialect/postgresql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ impl Dialect for PostgreSqlDialect {
192192
fn supports_nested_comments(&self) -> bool {
193193
true
194194
}
195+
196+
fn supports_string_escape_constant(&self) -> bool {
197+
true
198+
}
195199
}
196200

197201
pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {

src/dialect/redshift.rs

+4
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,8 @@ impl Dialect for RedshiftSqlDialect {
6868
fn supports_connect_by(&self) -> bool {
6969
true
7070
}
71+
72+
fn supports_string_escape_constant(&self) -> bool {
73+
true
74+
}
7175
}

src/test_utils.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -218,13 +218,17 @@ impl TestedDialects {
218218

219219
/// Check that the tokenizer returns the expected tokens for the given SQL.
220220
pub fn tokenizes_to(&self, sql: &str, expected: Vec<Token>) {
221+
if self.dialects.is_empty() {
222+
panic!("No dialects to test");
223+
}
224+
221225
self.dialects.iter().for_each(|dialect| {
222226
let mut tokenizer = Tokenizer::new(&**dialect, sql);
223227
if let Some(options) = &self.options {
224228
tokenizer = tokenizer.with_unescape(options.unescape);
225229
}
226230
let tokens = tokenizer.tokenize().unwrap();
227-
assert_eq!(expected, tokens);
231+
assert_eq!(expected, tokens, "Tokenized differently for {:?}", dialect);
228232
});
229233
}
230234
}

src/tokenizer.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ impl<'a> Tokenizer<'a> {
790790
}
791791
}
792792
// PostgreSQL accepts "escape" string constants, which are an extension to the SQL standard.
793-
x @ 'e' | x @ 'E' => {
793+
x @ 'e' | x @ 'E' if self.dialect.supports_string_escape_constant() => {
794794
let starting_loc = chars.location();
795795
chars.next(); // consume, to check the next char
796796
match chars.peek() {
@@ -3244,4 +3244,48 @@ mod tests {
32443244
],
32453245
);
32463246
}
3247+
3248+
#[test]
3249+
fn test_string_escape_constant_not_supported() {
3250+
all_dialects_where(|dialect| !dialect.supports_string_escape_constant()).tokenizes_to(
3251+
"select e'...'",
3252+
vec![
3253+
Token::make_keyword("select"),
3254+
Token::Whitespace(Whitespace::Space),
3255+
Token::make_word("e", None),
3256+
Token::SingleQuotedString("...".to_string()),
3257+
],
3258+
);
3259+
3260+
all_dialects_where(|dialect| !dialect.supports_string_escape_constant()).tokenizes_to(
3261+
"select E'...'",
3262+
vec![
3263+
Token::make_keyword("select"),
3264+
Token::Whitespace(Whitespace::Space),
3265+
Token::make_word("E", None),
3266+
Token::SingleQuotedString("...".to_string()),
3267+
],
3268+
);
3269+
}
3270+
3271+
#[test]
3272+
fn test_string_escape_constant_supported() {
3273+
all_dialects_where(|dialect| dialect.supports_string_escape_constant()).tokenizes_to(
3274+
"select e'\\''",
3275+
vec![
3276+
Token::make_keyword("select"),
3277+
Token::Whitespace(Whitespace::Space),
3278+
Token::EscapedStringLiteral("'".to_string()),
3279+
],
3280+
);
3281+
3282+
all_dialects_where(|dialect| dialect.supports_string_escape_constant()).tokenizes_to(
3283+
"select E'\\''",
3284+
vec![
3285+
Token::make_keyword("select"),
3286+
Token::Whitespace(Whitespace::Space),
3287+
Token::EscapedStringLiteral("'".to_string()),
3288+
],
3289+
);
3290+
}
32473291
}

0 commit comments

Comments
 (0)