Skip to content

Commit 335669c

Browse files
committed
Made JSqlParserQueryEnhancer aware of MERGE statements.
Closes spring-projects#2641
1 parent 2266350 commit 335669c

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import net.sf.jsqlparser.schema.Column;
2727
import net.sf.jsqlparser.statement.Statement;
2828
import net.sf.jsqlparser.statement.delete.Delete;
29+
import net.sf.jsqlparser.statement.merge.Merge;
2930
import net.sf.jsqlparser.statement.insert.Insert;
3031
import net.sf.jsqlparser.statement.select.OrderByElement;
3132
import net.sf.jsqlparser.statement.select.PlainSelect;
@@ -57,6 +58,7 @@
5758
*
5859
* @author Diego Krupitza
5960
* @author Greg Turnquist
61+
* @author Geoffrey Deremetz
6062
* @since 2.7.0
6163
*/
6264
public class JSqlParserQueryEnhancer implements QueryEnhancer {
@@ -91,6 +93,8 @@ private ParsedType detectParsedType() {
9193
return ParsedType.DELETE;
9294
} else if (statement instanceof Select) {
9395
return ParsedType.SELECT;
96+
} else if (statement instanceof Merge) {
97+
return ParsedType.MERGE;
9498
} else {
9599
return ParsedType.SELECT;
96100
}
@@ -479,10 +483,11 @@ public DeclaredQuery getQuery() {
479483
* <li>{@code ParsedType.UPDATE}: means the top level statement is {@link Update}</li>
480484
* <li>{@code ParsedType.SELECT}: means the top level statement is {@link Select}</li>
481485
* <li>{@code ParsedType.INSERT}: means the top level statement is {@link Insert}</li>
486+
* <li>{@code ParsedType.MERGE}: means the top level statement is {@link Merge}</li>
482487
* </ul>
483488
*/
484489
enum ParsedType {
485-
DELETE, UPDATE, SELECT, INSERT;
490+
DELETE, UPDATE, SELECT, INSERT, MERGE;
486491
}
487492

488493
}

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
* @author Diego Krupitza
8484
* @author Daniel Shuy
8585
* @author Simon Paradies
86+
* @author Geoffrey Deremetz
8687
*/
8788
@ExtendWith(SpringExtension.class)
8889
@ContextConfiguration("classpath:application-context.xml")
@@ -3002,6 +3003,22 @@ void insertStatementModifyingQueryWithParamsWorks() {
30023003
.contains("Gierke", "Arrasz", "Matthews", "raymond", testLastName);
30033004
}
30043005

3006+
@Test // GH-2641
3007+
void mergeWithNativeStatement() {
3008+
3009+
flushTestUsers();
3010+
3011+
Optional<User> byIdUser = repository.findById(firstUser.getId());
3012+
assertThat(byIdUser).isPresent().map(User::getAge).get().isEqualTo(28);
3013+
3014+
// when
3015+
repository.mergeNativeStatement();
3016+
3017+
// then
3018+
Optional<User> afterUpdate = repository.findById(firstUser.getId());
3019+
assertThat(afterUpdate).isPresent().map(User::getAge).get().isEqualTo(30);
3020+
}
3021+
30053022
private Page<User> executeSpecWithSort(Sort sort) {
30063023

30073024
flushTestUsers();

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java

+13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* Unit tests for {@link QueryEnhancer}.
3737
*
3838
* @author Diego Krupitza
39+
* @author Geoffrey Deremetz
3940
*/
4041
class QueryEnhancerUnitTests {
4142

@@ -920,6 +921,18 @@ void insertStatementIsProcessedSameAsDefault(String insertQuery) {
920921
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
921922
}
922923

924+
@Test // GH-2641
925+
void mergeStatementWorksWithJSqlParser() {
926+
String query = "merge into a using (select id, value from b) query on (a.id = query.id) when matched then update set a.value = value";
927+
StringQuery stringQuery = new StringQuery(query, true);
928+
QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
929+
930+
assertThat(queryEnhancer.getJoinAliases()).isEmpty();
931+
assertThat(queryEnhancer.detectAlias()).isNull();
932+
assertThat(queryEnhancer.getProjection()).isEmpty();
933+
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
934+
}
935+
923936
public static Stream<Arguments> insertStatementIsProcessedSameAsDefaultSource() {
924937
return Stream.of( //
925938
Arguments.of("INSERT INTO FOO(A) VALUES('A')"), //

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java

+11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
* @author Greg Turnquist
4444
* @author Simon Paradies
4545
* @author Diego Krupitza
46+
* @author Geoffrey Deremetz
4647
*/
4748
public interface UserRepository
4849
extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User>, UserRepositoryCustom {
@@ -681,6 +682,16 @@ List<String> findAllAndSortByFunctionResultNamedParameter(@Param("namedParameter
681682
nativeQuery = true)
682683
void insertNewUserWithParamNativeQuery(@Param("lastname") String lastname);
683684

685+
// GH-2641
686+
@Modifying(clearAutomatically = true)
687+
@Query(value = "merge into sd_user " +
688+
"using (select id from sd_user where age < 30) request " +
689+
"on (sd_user.id = request.id) " +
690+
"when matched then " +
691+
" update set sd_user.age = 30",
692+
nativeQuery = true)
693+
int mergeNativeStatement();
694+
684695
interface RolesAndFirstname {
685696

686697
String getFirstname();

0 commit comments

Comments
 (0)