1
1
/*
2
- * Copyright 2002-2024 the original author or authors.
2
+ * Copyright 2002-2025 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
16
16
17
17
package org .springframework .r2dbc .core ;
18
18
19
- import java .util .Arrays ;
20
- import java .util .Collections ;
21
19
import java .util .HashMap ;
22
- import java .util .LinkedHashMap ;
20
+ import java .util .List ;
23
21
import java .util .Map ;
24
22
25
23
import io .r2dbc .spi .Parameters ;
24
+ import org .junit .jupiter .api .Disabled ;
26
25
import org .junit .jupiter .api .Test ;
27
26
import org .junit .jupiter .params .ParameterizedTest ;
28
27
import org .junit .jupiter .params .provider .ValueSource ;
42
41
* @author Mark Paluch
43
42
* @author Jens Schauder
44
43
* @author Anton Naydenov
44
+ * @author Sam Brannen
45
45
*/
46
46
class NamedParameterUtilsTests {
47
47
48
- private final BindMarkersFactory BIND_MARKERS = BindMarkersFactory .indexed ("$" , 1 );
48
+ private static final BindMarkersFactory INDEXED_MARKERS = BindMarkersFactory .indexed ("$" , 1 );
49
+
50
+ private static final BindMarkersFactory ANONYMOUS_MARKERS = BindMarkersFactory .anonymous ("?" );
49
51
50
52
51
53
@ Test
@@ -73,7 +75,7 @@ void substituteNamedParameters() {
73
75
namedParams .addValue ("a" , "a" ).addValue ("b" , "b" ).addValue ("c" , "c" );
74
76
75
77
PreparedOperation <?> operation = NamedParameterUtils .substituteNamedParameters (
76
- "xxx :a :b :c" , BIND_MARKERS , namedParams );
78
+ "xxx :a :b :c" , INDEXED_MARKERS , namedParams );
77
79
78
80
assertThat (operation .toQuery ()).isEqualTo ("xxx $1 $2 $3" );
79
81
@@ -87,11 +89,11 @@ void substituteNamedParameters() {
87
89
void substituteObjectArray () {
88
90
MapBindParameterSource namedParams = new MapBindParameterSource (new HashMap <>());
89
91
namedParams .addValue ("a" ,
90
- Arrays . asList (new Object [] {"Walter" , "Heisenberg" },
91
- new Object [] {"Walt Jr." , "Flynn" }));
92
+ List . of (new Object [] {"Walter" , "Heisenberg" },
93
+ new Object [] {"Walt Jr." , "Flynn" }));
92
94
93
95
PreparedOperation <?> operation = NamedParameterUtils .substituteNamedParameters (
94
- "xxx :a" , BIND_MARKERS , namedParams );
96
+ "xxx :a" , INDEXED_MARKERS , namedParams );
95
97
96
98
assertThat (operation .toQuery ()).isEqualTo ("xxx ($1, $2), ($3, $4)" );
97
99
}
@@ -100,13 +102,13 @@ void substituteObjectArray() {
100
102
void shouldBindObjectArray () {
101
103
MapBindParameterSource namedParams = new MapBindParameterSource (new HashMap <>());
102
104
namedParams .addValue ("a" ,
103
- Arrays . asList (new Object [] {"Walter" , "Heisenberg" },
104
- new Object [] {"Walt Jr." , "Flynn" }));
105
+ List . of (new Object [] {"Walter" , "Heisenberg" },
106
+ new Object [] {"Walt Jr." , "Flynn" }));
105
107
106
108
BindTarget bindTarget = mock ();
107
109
108
110
PreparedOperation <?> operation = NamedParameterUtils .substituteNamedParameters (
109
- "xxx :a" , BIND_MARKERS , namedParams );
111
+ "xxx :a" , INDEXED_MARKERS , namedParams );
110
112
operation .bindTo (bindTarget );
111
113
112
114
verify (bindTarget ).bind (0 , "Walter" );
@@ -141,7 +143,7 @@ void parseSqlStatementWithPostgresCasting() {
141
143
142
144
ParsedSql parsedSql = NamedParameterUtils .parseSqlStatement (sql );
143
145
PreparedOperation <?> operation = NamedParameterUtils .substituteNamedParameters (
144
- parsedSql , BIND_MARKERS , new MapBindParameterSource ());
146
+ parsedSql , INDEXED_MARKERS , new MapBindParameterSource ());
145
147
146
148
assertThat (operation .toQuery ()).isEqualTo (expectedSql );
147
149
}
@@ -312,14 +314,13 @@ void shouldAllowParsingMultipleUseOfParameter() {
312
314
void multipleEqualParameterReferencesBindsValueOnce () {
313
315
String sql = "SELECT * FROM person where name = :id or lastname = :id" ;
314
316
315
- BindMarkersFactory factory = BindMarkersFactory .indexed ("$" , 0 );
317
+ MapBindParameterSource source = new MapBindParameterSource (Map .of ("id" , Parameters .in ("foo" )));
318
+ PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (sql , INDEXED_MARKERS , source );
316
319
317
- PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (
318
- sql , factory , new MapBindParameterSource (
319
- Collections .singletonMap ("id" , Parameters .in ("foo" ))));
320
+ assertThat (operation .toQuery ())
321
+ .isEqualTo ("SELECT * FROM person where name = $1 or lastname = $1" );
320
322
321
- assertThat (operation .toQuery ()).isEqualTo (
322
- "SELECT * FROM person where name = $0 or lastname = $0" );
323
+ Map <Integer , Object > bindings = new HashMap <>();
323
324
324
325
operation .bindTo (new BindTarget () {
325
326
@ Override
@@ -328,8 +329,7 @@ public void bind(String identifier, Object value) {
328
329
}
329
330
@ Override
330
331
public void bind (int index , Object value ) {
331
- assertThat (index ).isEqualTo (0 );
332
- assertThat (value ).isEqualTo (Parameters .in ("foo" ));
332
+ bindings .put (index , value );
333
333
}
334
334
@ Override
335
335
public void bindNull (String identifier , Class <?> type ) {
@@ -340,22 +340,24 @@ public void bindNull(int index, Class<?> type) {
340
340
throw new UnsupportedOperationException ();
341
341
}
342
342
});
343
+
344
+ assertThat (bindings )
345
+ .hasSize (1 )
346
+ .containsEntry (0 , Parameters .in ("foo" ));
343
347
}
344
348
345
349
@ Test
346
- void multipleEqualCollectionParameterReferencesBindsValueOnce () {
350
+ void multipleEqualCollectionParameterReferencesForIndexedMarkersBindsValueOnce () {
347
351
String sql = "SELECT * FROM person where name IN (:ids) or lastname IN (:ids)" ;
348
352
349
- BindMarkersFactory factory = BindMarkersFactory . indexed ( "$" , 0 );
350
-
351
- MultiValueMap < Integer , Object > bindings = new LinkedMultiValueMap <>( );
353
+ MapBindParameterSource source = new MapBindParameterSource ( Map . of ( "ids" ,
354
+ Parameters . in ( List . of ( "foo" , "bar" , "baz" ))));
355
+ PreparedOperation < String > operation = NamedParameterUtils . substituteNamedParameters ( sql , INDEXED_MARKERS , source );
352
356
353
- PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (
354
- sql , factory , new MapBindParameterSource (Collections .singletonMap ("ids" ,
355
- Parameters .in (Arrays .asList ("foo" , "bar" , "baz" )))));
357
+ assertThat (operation .toQuery ())
358
+ .isEqualTo ("SELECT * FROM person where name IN ($1, $2, $3) or lastname IN ($1, $2, $3)" );
356
359
357
- assertThat (operation .toQuery ()).isEqualTo (
358
- "SELECT * FROM person where name IN ($0, $1, $2) or lastname IN ($0, $1, $2)" );
360
+ MultiValueMap <Integer , Object > bindings = new LinkedMultiValueMap <>();
359
361
360
362
operation .bindTo (new BindTarget () {
361
363
@ Override
@@ -364,8 +366,6 @@ public void bind(String identifier, Object value) {
364
366
}
365
367
@ Override
366
368
public void bind (int index , Object value ) {
367
- assertThat (index ).isIn (0 , 1 , 2 );
368
- assertThat (value ).isIn ("foo" , "bar" , "baz" );
369
369
bindings .add (index , value );
370
370
}
371
371
@ Override
@@ -378,25 +378,63 @@ public void bindNull(int index, Class<?> type) {
378
378
}
379
379
});
380
380
381
- assertThat (bindings ).containsEntry (0 , Collections .singletonList ("foo" )) //
382
- .containsEntry (1 , Collections .singletonList ("bar" )) //
383
- .containsEntry (2 , Collections .singletonList ("baz" ));
381
+ assertThat (bindings )
382
+ .hasSize (3 )
383
+ .containsEntry (0 , List .of ("foo" ))
384
+ .containsEntry (1 , List .of ("bar" ))
385
+ .containsEntry (2 , List .of ("baz" ));
386
+ }
387
+
388
+ @ Test // gh-34768
389
+ @ Disabled ("Disabled until gh-34768 is addressed" )
390
+ void multipleEqualCollectionParameterReferencesForAnonymousMarkersBindsValueTwice () {
391
+ String sql = "SELECT * FROM fund_info WHERE fund_code IN (:fundCodes) OR fund_code IN (:fundCodes)" ;
392
+
393
+ MapBindParameterSource source = new MapBindParameterSource (Map .of ("fundCodes" , Parameters .in (List .of ("foo" ))));
394
+ PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (sql , ANONYMOUS_MARKERS , source );
395
+
396
+ assertThat (operation .toQuery ())
397
+ .isEqualTo ("SELECT * FROM fund_info WHERE fund_code IN (?) OR fund_code IN (?)" );
398
+
399
+ Map <Integer , Object > bindings = new HashMap <>();
400
+
401
+ operation .bindTo (new BindTarget () {
402
+ @ Override
403
+ public void bind (String identifier , Object value ) {}
404
+
405
+ @ Override
406
+ public void bind (int index , Object value ) {
407
+ bindings .put (index , value );
408
+ }
409
+
410
+ @ Override
411
+ public void bindNull (String identifier , Class <?> type ) {
412
+ throw new UnsupportedOperationException ();
413
+ }
414
+
415
+ @ Override
416
+ public void bindNull (int index , Class <?> type ) {
417
+ throw new UnsupportedOperationException ();
418
+ }
419
+ });
420
+
421
+ assertThat (bindings )
422
+ .hasSize (2 )
423
+ .containsEntry (0 , "foo" )
424
+ .containsEntry (1 , "foo" );
384
425
}
385
426
386
427
@ Test
387
- void multipleEqualParameterReferencesForAnonymousMarkersBindsValueMultipleTimes () {
428
+ void multipleEqualParameterReferencesForAnonymousMarkersBindsValueTwice () {
388
429
String sql = "SELECT * FROM person where name = :id or lastname = :id" ;
389
430
390
- BindMarkersFactory factory = BindMarkersFactory .anonymous ("?" );
391
-
392
- PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (
393
- sql , factory , new MapBindParameterSource (
394
- Collections .singletonMap ("id" , Parameters .in ("foo" ))));
431
+ MapBindParameterSource source = new MapBindParameterSource (Map .of ("id" , Parameters .in ("foo" )));
432
+ PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (sql , ANONYMOUS_MARKERS , source );
395
433
396
- assertThat (operation .toQuery ()). isEqualTo (
397
- "SELECT * FROM person where name = ? or lastname = ?" );
434
+ assertThat (operation .toQuery ())
435
+ . isEqualTo ( "SELECT * FROM person where name = ? or lastname = ?" );
398
436
399
- Map <Integer , Object > bindValues = new LinkedHashMap <>();
437
+ Map <Integer , Object > bindings = new HashMap <>();
400
438
401
439
operation .bindTo (new BindTarget () {
402
440
@ Override
@@ -405,7 +443,7 @@ public void bind(String identifier, Object value) {
405
443
}
406
444
@ Override
407
445
public void bind (int index , Object value ) {
408
- bindValues .put (index , value );
446
+ bindings .put (index , value );
409
447
}
410
448
@ Override
411
449
public void bindNull (String identifier , Class <?> type ) {
@@ -417,21 +455,23 @@ public void bindNull(int index, Class<?> type) {
417
455
}
418
456
});
419
457
420
- assertThat (bindValues ).hasSize (2 ).containsEntry (0 , Parameters .in ("foo" )).containsEntry (1 , Parameters .in ("foo" ));
458
+ assertThat (bindings )
459
+ .hasSize (2 )
460
+ .containsEntry (0 , Parameters .in ("foo" ))
461
+ .containsEntry (1 , Parameters .in ("foo" ));
421
462
}
422
463
423
464
@ Test
424
465
void multipleEqualParameterReferencesBindsNullOnce () {
425
466
String sql = "SELECT * FROM person where name = :id or lastname = :id" ;
426
467
427
- BindMarkersFactory factory = BindMarkersFactory .indexed ("$" , 0 );
468
+ MapBindParameterSource source = new MapBindParameterSource (Map .of ("id" , Parameters .in (String .class )));
469
+ PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (sql , INDEXED_MARKERS , source );
428
470
429
- PreparedOperation <String > operation = NamedParameterUtils .substituteNamedParameters (
430
- sql , factory , new MapBindParameterSource (
431
- Collections .singletonMap ("id" , Parameters .in (String .class ))));
471
+ assertThat (operation .toQuery ())
472
+ .isEqualTo ("SELECT * FROM person where name = $1 or lastname = $1" );
432
473
433
- assertThat (operation .toQuery ()).isEqualTo (
434
- "SELECT * FROM person where name = $0 or lastname = $0" );
474
+ Map <Integer , Object > bindings = new HashMap <>();
435
475
436
476
operation .bindTo (new BindTarget () {
437
477
@ Override
@@ -440,8 +480,7 @@ public void bind(String identifier, Object value) {
440
480
}
441
481
@ Override
442
482
public void bind (int index , Object value ) {
443
- assertThat (index ).isEqualTo (0 );
444
- assertThat (value ).isEqualTo (Parameters .in (String .class ));
483
+ bindings .put (index , value );
445
484
}
446
485
@ Override
447
486
public void bindNull (String identifier , Class <?> type ) {
@@ -452,16 +491,20 @@ public void bindNull(int index, Class<?> type) {
452
491
throw new UnsupportedOperationException ();
453
492
}
454
493
});
494
+
495
+ assertThat (bindings )
496
+ .hasSize (1 )
497
+ .containsEntry (0 , Parameters .in (String .class ));
455
498
}
456
499
457
500
458
- private String expand (ParsedSql sql ) {
459
- return NamedParameterUtils .substituteNamedParameters (sql , BIND_MARKERS ,
501
+ private static String expand (ParsedSql sql ) {
502
+ return NamedParameterUtils .substituteNamedParameters (sql , INDEXED_MARKERS ,
460
503
new MapBindParameterSource ()).toQuery ();
461
504
}
462
505
463
- private String expand (String sql ) {
464
- return NamedParameterUtils .substituteNamedParameters (sql , BIND_MARKERS ,
506
+ private static String expand (String sql ) {
507
+ return NamedParameterUtils .substituteNamedParameters (sql , INDEXED_MARKERS ,
465
508
new MapBindParameterSource ()).toQuery ();
466
509
}
467
510
0 commit comments