Skip to content

Fix tests pass #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,10 @@ pub enum IsCheck {
NULL,
FALSE,
TRUE,
UNKNOWN
UNKNOWN,
}

impl fmt::Display for IsCheck{
impl fmt::Display for IsCheck {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IsCheck::NULL => write!(f, "NULL"),
Expand Down
2 changes: 1 addition & 1 deletion src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ impl fmt::Display for Join {
_ => "",
}
}

#[allow(clippy::needless_lifetimes)]
fn suffix<'a>(constraint: &'a JoinConstraint) -> impl fmt::Display + 'a {
struct Suffix<'a>(&'a JoinConstraint);
Expand Down
23 changes: 21 additions & 2 deletions src/ast/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Value::Number(v) => write!(f, "{}", v),
Value::SingleQuotedString(v) => write!(f, "'{}'", v),
Value::DoubleQuotedString(v) => write!(f, "\"{}\"", v),
Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
Value::DoubleQuotedString(v) => write!(f, "\"{}\"", escape_double_quote_string(v)),
Value::RegexLiteral { ref value, quote } => write!(f, "{}{}{}", quote, value, quote),
Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
Value::HexStringLiteral(v) => write!(f, "X'{}'", v),
Expand Down Expand Up @@ -190,6 +190,25 @@ impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
}
}

pub struct EscapeDoubleQuoteString<'a>(&'a str);

impl<'a> fmt::Display for EscapeDoubleQuoteString<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for c in self.0.chars() {
if c == '"' {
write!(f, "\"\"")?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I think there's an issue here that warehouses have different ways of escaping some characters? for instance I think some escape " as "" and others escape " as \".

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this is still fine here though? are you pretty sure about this case?

eventually we should get in tests for all the cases that triggered the modifications added in this fork. I have a file with a bunch of them... I'd thought I had committed it but I guess not. https://gist.github.com/donhcd/31de459c6cfe763dce44f78a2246b172

anyways if you feel good about this let's try it out and we'll make sure we don't have any regressions before we move qwill to use an updated sha

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So line 68 used to have the escape_single_quote_string, which is why I'm reintroducing it here. This was why the test was failing (because the formatting for Value used to have this, which is what the below test is checking for and failing). I want to reintroduce this invocation, and also introduce the parallel for double-quoted strings, which is a feature that was introduced by us.

In order to handle the various quote-escaping mechanisms, I think SingleQuotedString and DoubleQuotedString will need to have another field which denotes the quote char, so that formatting will know how to format it out. I think that should come after the regression is fixed.

} else {
write!(f, "{}", c)?;
}
}
Ok(())
}
}

pub fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> {
EscapeSingleQuoteString(s)
}

pub fn escape_double_quote_string(s: &str) -> EscapeDoubleQuoteString<'_> {
EscapeDoubleQuoteString(s)
}
6 changes: 5 additions & 1 deletion src/dialect/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ pub struct GenericDialect;

impl Dialect for GenericDialect {
fn is_identifier_start(&self, ch: char) -> bool {
('a'..='z').contains(&ch) || ('A'..='Z').contains(&ch) || ch == '_' || ch == '#' || ch == '@'
('a'..='z').contains(&ch)
|| ('A'..='Z').contains(&ch)
|| ch == '_'
|| ch == '#'
|| ch == '@'
}

fn is_identifier_part(&self, ch: char) -> bool {
Expand Down
6 changes: 3 additions & 3 deletions src/dialect/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,11 +496,11 @@ define_keywords!(
WEDNESDAY,
WEEK,
WEEKDAY,
WEEKDAY_ISO,
WEEKISO,
WEEKOFYEAR,
WEEKOFYEARISO,
WEEKOFYEAR_ISO,
WEEKISO,
WEEKDAY_ISO,
WEEK_ISO,
WHEN,
WHENEVER,
Expand All @@ -511,8 +511,8 @@ define_keywords!(
WITHIN,
WITHOUT,
WK,
WOY,
WORK,
WOY,
WRITE,
WY,
Y,
Expand Down
6 changes: 5 additions & 1 deletion src/dialect/mssql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ impl Dialect for MsSqlDialect {
fn is_identifier_start(&self, ch: char) -> bool {
// See https://docs.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-2017#rules-for-regular-identifiers
// We don't support non-latin "letters" currently.
('a'..='z').contains(&ch) || ('A'..='Z').contains(&ch) || ch == '_' || ch == '#' || ch == '@'
('a'..='z').contains(&ch)
|| ('A'..='Z').contains(&ch)
|| ch == '_'
|| ch == '#'
|| ch == '@'
}

fn is_identifier_part(&self, ch: char) -> bool {
Expand Down
16 changes: 11 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,9 @@ impl<'a> Parser<'a> {
} else if self.parse_keyword(Keyword::BETWEEN) {
Ok((self.parse_between(expr, negated)?, true))
} else if self.parse_keyword(Keyword::LIKE) {
Ok((self.parse_like(expr, true, negated)?, true))
Ok((self.parse_like(expr, true, negated, precedence)?, true))
} else if self.parse_keyword(Keyword::ILIKE) {
Ok((self.parse_like(expr, false, negated)?, true))
Ok((self.parse_like(expr, false, negated, precedence)?, true))
} else if self.parse_keywords(&[Keyword::SIMILAR, Keyword::TO]) {
Ok((self.parse_similar(expr, negated)?, true))
} else {
Expand Down Expand Up @@ -1067,10 +1067,11 @@ impl<'a> Parser<'a> {
expr: Expr,
case_sensitive: bool,
negated: bool,
precedence: u8,
) -> Result<Expr, ParserError> {
let pat = self.parse_expr()?;
let pat = self.parse_subexpr(precedence)?;
let esc = if self.parse_keyword(Keyword::ESCAPE) {
Some(self.parse_expr()?)
Some(self.parse_subexpr(precedence)?)
} else {
None
};
Expand Down Expand Up @@ -1936,6 +1937,9 @@ impl<'a> Parser<'a> {
}

pub fn preceding_toks(&self) -> String {
if self.tokens.is_empty() {
return "".to_string();
}
let slice_start = if self.index < 20 { 0 } else { self.index - 20 };
let slice_end = if self.index >= self.tokens.len() {
self.tokens.len() - 1
Expand Down Expand Up @@ -2596,7 +2600,9 @@ impl<'a> Parser<'a> {
// followed by some joins or (B) another level of nesting.
let mut table_and_joins = self.parse_table_and_joins()?;

if !table_and_joins.joins.is_empty() || matches!(&table_and_joins.relation, TableFactor::NestedJoin(_)) {
if !table_and_joins.joins.is_empty()
|| matches!(&table_and_joins.relation, TableFactor::NestedJoin(_))
{
// (B): `table_and_joins` (what we found inside the parentheses)
// is a nested join `(foo JOIN bar)`, not followed by other joins.
self.expect_token(&Token::RParen)?;
Expand Down
3 changes: 1 addition & 2 deletions src/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ impl<'a> Tokenizer<'a> {
match ch {
// allow backslash to escape the next character, whatever it is
'\\' => {
s.push('\\');
chars.next(); // consume the escape char
if let Some(next_ch) = chars.next() {
s.push(next_ch);
}
Expand All @@ -739,7 +739,6 @@ impl<'a> Tokenizer<'a> {
&& ch == quote_ch
&& next_char_is_quote =>
{
s.push(quote_ch);
s.push(quote_ch);
chars.next(); // consume quote_ch
}
Expand Down
Loading