@@ -152,6 +152,168 @@ fn parse_kill() {
152
152
) ;
153
153
}
154
154
155
+ #[ test]
156
+ fn parse_delimited_identifiers ( ) {
157
+ // check that quoted identifiers in any position remain quoted after serialization
158
+ let select = clickhouse ( ) . verified_only_select (
159
+ r#"SELECT "alias"."bar baz", "myfun"(), "simple id" AS "column alias" FROM "a table" AS "alias""# ,
160
+ ) ;
161
+ // check FROM
162
+ match only ( select. from ) . relation {
163
+ TableFactor :: Table {
164
+ name,
165
+ alias,
166
+ args,
167
+ with_hints,
168
+ } => {
169
+ assert_eq ! ( vec![ Ident :: with_quote( '"' , "a table" ) ] , name. 0 ) ;
170
+ assert_eq ! ( Ident :: with_quote( '"' , "alias" ) , alias. unwrap( ) . name) ;
171
+ assert ! ( args. is_none( ) ) ;
172
+ assert ! ( with_hints. is_empty( ) ) ;
173
+ }
174
+ _ => panic ! ( "Expecting TableFactor::Table" ) ,
175
+ }
176
+ // check SELECT
177
+ assert_eq ! ( 3 , select. projection. len( ) ) ;
178
+ assert_eq ! (
179
+ & Expr :: CompoundIdentifier ( vec![
180
+ Ident :: with_quote( '"' , "alias" ) ,
181
+ Ident :: with_quote( '"' , "bar baz" ) ,
182
+ ] ) ,
183
+ expr_from_projection( & select. projection[ 0 ] ) ,
184
+ ) ;
185
+ assert_eq ! (
186
+ & Expr :: Function ( Function {
187
+ name: ObjectName ( vec![ Ident :: with_quote( '"' , "myfun" ) ] ) ,
188
+ args: vec![ ] ,
189
+ over: None ,
190
+ distinct: false ,
191
+ special: false ,
192
+ } ) ,
193
+ expr_from_projection( & select. projection[ 1 ] ) ,
194
+ ) ;
195
+ match & select. projection [ 2 ] {
196
+ SelectItem :: ExprWithAlias { expr, alias } => {
197
+ assert_eq ! ( & Expr :: Identifier ( Ident :: with_quote( '"' , "simple id" ) ) , expr) ;
198
+ assert_eq ! ( & Ident :: with_quote( '"' , "column alias" ) , alias) ;
199
+ }
200
+ _ => panic ! ( "Expected ExprWithAlias" ) ,
201
+ }
202
+
203
+ clickhouse ( ) . verified_stmt ( r#"CREATE TABLE "foo" ("bar" "int")"# ) ;
204
+ clickhouse ( ) . verified_stmt ( r#"ALTER TABLE foo ADD CONSTRAINT "bar" PRIMARY KEY (baz)"# ) ;
205
+ //TODO verified_stmt(r#"UPDATE foo SET "bar" = 5"#);
206
+ }
207
+
208
+ #[ test]
209
+ fn parse_like ( ) {
210
+ fn chk ( negated : bool ) {
211
+ let sql = & format ! (
212
+ "SELECT * FROM customers WHERE name {}LIKE '%a'" ,
213
+ if negated { "NOT " } else { "" }
214
+ ) ;
215
+ let select = clickhouse ( ) . verified_only_select ( sql) ;
216
+ assert_eq ! (
217
+ Expr :: Like {
218
+ expr: Box :: new( Expr :: Identifier ( Ident :: new( "name" ) ) ) ,
219
+ negated,
220
+ pattern: Box :: new( Expr :: Value ( Value :: SingleQuotedString ( "%a" . to_string( ) ) ) ) ,
221
+ escape_char: None ,
222
+ } ,
223
+ select. selection. unwrap( )
224
+ ) ;
225
+
226
+ // Test with escape char
227
+ let sql = & format ! (
228
+ "SELECT * FROM customers WHERE name {}LIKE '%a' ESCAPE '\\ '" ,
229
+ if negated { "NOT " } else { "" }
230
+ ) ;
231
+ let select = clickhouse ( ) . verified_only_select ( sql) ;
232
+ assert_eq ! (
233
+ Expr :: Like {
234
+ expr: Box :: new( Expr :: Identifier ( Ident :: new( "name" ) ) ) ,
235
+ negated,
236
+ pattern: Box :: new( Expr :: Value ( Value :: SingleQuotedString ( "%a" . to_string( ) ) ) ) ,
237
+ escape_char: Some ( '\\' ) ,
238
+ } ,
239
+ select. selection. unwrap( )
240
+ ) ;
241
+
242
+ // This statement tests that LIKE and NOT LIKE have the same precedence.
243
+ // This was previously mishandled (#81).
244
+ let sql = & format ! (
245
+ "SELECT * FROM customers WHERE name {}LIKE '%a' IS NULL" ,
246
+ if negated { "NOT " } else { "" }
247
+ ) ;
248
+ let select = clickhouse ( ) . verified_only_select ( sql) ;
249
+ assert_eq ! (
250
+ Expr :: IsNull ( Box :: new( Expr :: Like {
251
+ expr: Box :: new( Expr :: Identifier ( Ident :: new( "name" ) ) ) ,
252
+ negated,
253
+ pattern: Box :: new( Expr :: Value ( Value :: SingleQuotedString ( "%a" . to_string( ) ) ) ) ,
254
+ escape_char: None ,
255
+ } ) ) ,
256
+ select. selection. unwrap( )
257
+ ) ;
258
+ }
259
+ chk ( false ) ;
260
+ chk ( true ) ;
261
+ }
262
+
263
+ #[ test]
264
+ fn parse_similar_to ( ) {
265
+ fn chk ( negated : bool ) {
266
+ let sql = & format ! (
267
+ "SELECT * FROM customers WHERE name {}SIMILAR TO '%a'" ,
268
+ if negated { "NOT " } else { "" }
269
+ ) ;
270
+ let select = clickhouse ( ) . verified_only_select ( sql) ;
271
+ assert_eq ! (
272
+ Expr :: SimilarTo {
273
+ expr: Box :: new( Expr :: Identifier ( Ident :: new( "name" ) ) ) ,
274
+ negated,
275
+ pattern: Box :: new( Expr :: Value ( Value :: SingleQuotedString ( "%a" . to_string( ) ) ) ) ,
276
+ escape_char: None ,
277
+ } ,
278
+ select. selection. unwrap( )
279
+ ) ;
280
+
281
+ // Test with escape char
282
+ let sql = & format ! (
283
+ "SELECT * FROM customers WHERE name {}SIMILAR TO '%a' ESCAPE '\\ '" ,
284
+ if negated { "NOT " } else { "" }
285
+ ) ;
286
+ let select = clickhouse ( ) . verified_only_select ( sql) ;
287
+ assert_eq ! (
288
+ Expr :: SimilarTo {
289
+ expr: Box :: new( Expr :: Identifier ( Ident :: new( "name" ) ) ) ,
290
+ negated,
291
+ pattern: Box :: new( Expr :: Value ( Value :: SingleQuotedString ( "%a" . to_string( ) ) ) ) ,
292
+ escape_char: Some ( '\\' ) ,
293
+ } ,
294
+ select. selection. unwrap( )
295
+ ) ;
296
+
297
+ // This statement tests that SIMILAR TO and NOT SIMILAR TO have the same precedence.
298
+ let sql = & format ! (
299
+ "SELECT * FROM customers WHERE name {}SIMILAR TO '%a' ESCAPE '\\ ' IS NULL" ,
300
+ if negated { "NOT " } else { "" }
301
+ ) ;
302
+ let select = clickhouse ( ) . verified_only_select ( sql) ;
303
+ assert_eq ! (
304
+ Expr :: IsNull ( Box :: new( Expr :: SimilarTo {
305
+ expr: Box :: new( Expr :: Identifier ( Ident :: new( "name" ) ) ) ,
306
+ negated,
307
+ pattern: Box :: new( Expr :: Value ( Value :: SingleQuotedString ( "%a" . to_string( ) ) ) ) ,
308
+ escape_char: Some ( '\\' ) ,
309
+ } ) ) ,
310
+ select. selection. unwrap( )
311
+ ) ;
312
+ }
313
+ chk ( false ) ;
314
+ chk ( true ) ;
315
+ }
316
+
155
317
fn clickhouse ( ) -> TestedDialects {
156
318
TestedDialects {
157
319
dialects : vec ! [ Box :: new( ClickHouseDialect { } ) ] ,
0 commit comments