File tree 4 files changed +47
-3
lines changed
4 files changed +47
-3
lines changed Original file line number Diff line number Diff line change @@ -111,7 +111,7 @@ impl ToString for ASTNode {
111
111
match self {
112
112
ASTNode :: SQLIdentifier ( s) => s. to_string ( ) ,
113
113
ASTNode :: SQLWildcard => "*" . to_string ( ) ,
114
- ASTNode :: SQLQualifiedWildcard ( q) => q. join ( "." ) + "*" ,
114
+ ASTNode :: SQLQualifiedWildcard ( q) => q. join ( "." ) + ". *" ,
115
115
ASTNode :: SQLCompoundIdentifier ( s) => s. join ( "." ) ,
116
116
ASTNode :: SQLIsNull ( ast) => format ! ( "{} IS NULL" , ast. as_ref( ) . to_string( ) ) ,
117
117
ASTNode :: SQLIsNotNull ( ast) => format ! ( "{} IS NOT NULL" , ast. as_ref( ) . to_string( ) ) ,
Original file line number Diff line number Diff line change @@ -35,7 +35,7 @@ impl ToString for Value {
35
35
Value :: Long ( v) => v. to_string ( ) ,
36
36
Value :: Double ( v) => v. to_string ( ) ,
37
37
Value :: Uuid ( v) => v. to_string ( ) ,
38
- Value :: SingleQuotedString ( v) => format ! ( "'{}'" , v ) ,
38
+ Value :: SingleQuotedString ( v) => format ! ( "'{}'" , escape_single_quote_string ( v ) ) ,
39
39
Value :: NationalStringLiteral ( v) => format ! ( "N'{}'" , v) ,
40
40
Value :: Boolean ( v) => v. to_string ( ) ,
41
41
Value :: Date ( v) => v. to_string ( ) ,
@@ -46,3 +46,15 @@ impl ToString for Value {
46
46
}
47
47
}
48
48
}
49
+
50
+ fn escape_single_quote_string ( s : & str ) -> String {
51
+ let mut escaped = String :: new ( ) ;
52
+ for c in s. chars ( ) {
53
+ if c == '\'' {
54
+ escaped. push_str ( "\' \' " ) ;
55
+ } else {
56
+ escaped. push ( c) ;
57
+ }
58
+ }
59
+ escaped
60
+ }
Original file line number Diff line number Diff line change @@ -462,7 +462,13 @@ impl<'a> Tokenizer<'a> {
462
462
match ch {
463
463
'\'' => {
464
464
chars. next ( ) ; // consume
465
- break ;
465
+ let escaped_quote = chars. peek ( ) . map ( |c| * c == '\'' ) . unwrap_or ( false ) ;
466
+ if escaped_quote {
467
+ s. push ( '\'' ) ;
468
+ chars. next ( ) ;
469
+ } else {
470
+ break ;
471
+ }
466
472
}
467
473
_ => {
468
474
chars. next ( ) ; // consume
Original file line number Diff line number Diff line change @@ -90,6 +90,13 @@ fn parse_select_wildcard() {
90
90
) ;
91
91
}
92
92
93
+ #[ test]
94
+ fn parse_count_wildcard ( ) {
95
+ verified_only_select (
96
+ "SELECT COUNT(Employee.*) FROM Order JOIN Employee ON Order.employee = Employee.id" ,
97
+ ) ;
98
+ }
99
+
93
100
#[ test]
94
101
fn parse_column_aliases ( ) {
95
102
let sql = "SELECT a.col + 1 AS newname FROM foo AS a" ;
@@ -147,6 +154,25 @@ fn parse_projection_nested_type() {
147
154
//TODO: add assertions
148
155
}
149
156
157
+ #[ test]
158
+ fn parse_escaped_single_quote_string_predicate ( ) {
159
+ use self :: ASTNode :: * ;
160
+ use self :: SQLOperator :: * ;
161
+ let sql = "SELECT id, fname, lname FROM customer \
162
+ WHERE salary != 'Jim''s salary'";
163
+ let ast = verified_only_select ( sql) ;
164
+ assert_eq ! (
165
+ Some ( SQLBinaryExpr {
166
+ left: Box :: new( SQLIdentifier ( "salary" . to_string( ) ) ) ,
167
+ op: NotEq ,
168
+ right: Box :: new( SQLValue ( Value :: SingleQuotedString (
169
+ "Jim's salary" . to_string( )
170
+ ) ) )
171
+ } ) ,
172
+ ast. selection,
173
+ ) ;
174
+ }
175
+
150
176
#[ test]
151
177
fn parse_compound_expr_1 ( ) {
152
178
use self :: ASTNode :: * ;
You can’t perform that action at this time.
0 commit comments