Skip to content

Commit 76157ce

Browse files
committed
Made JSqlParserQueryEnhancer aware of INSERT statements.
The `detectParsedType()` inside `JSqlParserQueryEnhancer` is now aware of `INSERT` statements, which means `INSERT` statements can now be used in native queries. Closes spring-projects#2593
1 parent 3a33cbc commit 76157ce

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

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

+6-2
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.insert.Insert;
2930
import net.sf.jsqlparser.statement.select.OrderByElement;
3031
import net.sf.jsqlparser.statement.select.PlainSelect;
3132
import net.sf.jsqlparser.statement.select.Select;
@@ -82,7 +83,9 @@ private ParsedType detectParsedType() {
8283
try {
8384
Statement statement = CCJSqlParserUtil.parse(this.query.getQueryString());
8485

85-
if (statement instanceof Update) {
86+
if (statement instanceof Insert) {
87+
return ParsedType.INSERT;
88+
} else if (statement instanceof Update) {
8689
return ParsedType.UPDATE;
8790
} else if (statement instanceof Delete) {
8891
return ParsedType.DELETE;
@@ -475,10 +478,11 @@ public DeclaredQuery getQuery() {
475478
* <li>{@code ParsedType.DELETE}: means the top level statement is {@link Delete}</li>
476479
* <li>{@code ParsedType.UPDATE}: means the top level statement is {@link Update}</li>
477480
* <li>{@code ParsedType.SELECT}: means the top level statement is {@link Select}</li>
481+
* <li>{@code ParsedType.INSERT}: means the top level statement is {@link Insert}</li>
478482
* </ul>
479483
*/
480484
enum ParsedType {
481-
DELETE, UPDATE, SELECT;
485+
DELETE, UPDATE, SELECT, INSERT;
482486
}
483487

484488
}

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

+29
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,35 @@ void complexWithNativeStatement() {
29682968
assertThat(foundData).containsExactly("joachim", "dave", "kevin");
29692969
}
29702970

2971+
@Test // GH-2593
2972+
void insertStatementModifyingQueryWorks() {
2973+
flushTestUsers();
2974+
repository.insertNewUserWithNativeQuery();
2975+
2976+
List<User> all = repository.findAll();
2977+
assertThat(all) //
2978+
.isNotNull() //
2979+
.isNotEmpty() //
2980+
.hasSize(5) //
2981+
.map(User::getLastname) //
2982+
.contains("Gierke", "Arrasz", "Matthews", "raymond", "K");
2983+
}
2984+
2985+
@Test // GH-2593
2986+
void insertStatementModifyingQueryWithParamsWorks() {
2987+
flushTestUsers();
2988+
String testLastName = "TestLastName";
2989+
repository.insertNewUserWithParamNativeQuery(testLastName);
2990+
2991+
List<User> all = repository.findAll();
2992+
assertThat(all) //
2993+
.isNotNull() //
2994+
.isNotEmpty() //
2995+
.hasSize(5) //
2996+
.map(User::getLastname) //
2997+
.contains("Gierke", "Arrasz", "Matthews", "raymond", testLastName);
2998+
}
2999+
29713000
private Page<User> executeSpecWithSort(Sort sort) {
29723001

29733002
flushTestUsers();

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

+38
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,44 @@ void multipleWithStatementsWorksWithJSQLParser() {
889889
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
890890
}
891891

892+
@ParameterizedTest // GH-2593
893+
@MethodSource("insertStatementIsProcessedSameAsDefaultSource")
894+
void insertStatementIsProcessedSameAsDefault(String insertQuery) {
895+
896+
StringQuery stringQuery = new StringQuery(insertQuery, true);
897+
QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
898+
899+
Sort sorting = Sort.by("day").descending();
900+
901+
// queryutils results
902+
String queryUtilsDetectAlias = QueryUtils.detectAlias(insertQuery);
903+
String queryUtilsProjection = QueryUtils.getProjection(insertQuery);
904+
String queryUtilsCountQuery = QueryUtils.createCountQueryFor(insertQuery);
905+
Set<String> queryUtilsOuterJoinAlias = QueryUtils.getOuterJoinAliases(insertQuery);
906+
907+
// direct access
908+
assertThat(stringQuery.getAlias()).isEqualToIgnoringCase(queryUtilsDetectAlias);
909+
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase(queryUtilsProjection);
910+
assertThat(stringQuery.hasConstructorExpression()).isFalse();
911+
912+
// access over enhancer
913+
assertThat(queryEnhancer.createCountQueryFor()).isEqualToIgnoringCase(queryUtilsCountQuery);
914+
assertThat(queryEnhancer.applySorting(sorting)).isEqualTo(insertQuery); // cant check with queryutils result since
915+
// query utils appens order by which is not
916+
// supported by sql standard.
917+
assertThat(queryEnhancer.getJoinAliases()).isEqualTo(queryUtilsOuterJoinAlias);
918+
assertThat(queryEnhancer.detectAlias()).isEqualToIgnoringCase(queryUtilsDetectAlias);
919+
assertThat(queryEnhancer.getProjection()).isEqualToIgnoringCase(queryUtilsProjection);
920+
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
921+
}
922+
923+
public static Stream<Arguments> insertStatementIsProcessedSameAsDefaultSource() {
924+
return Stream.of( //
925+
Arguments.of("INSERT INTO FOO(A) VALUES('A')"), //
926+
Arguments.of("INSERT INTO randomsecondTable(A,B,C,D) VALUES('A','B','C','D')") //
927+
);
928+
}
929+
892930
public static Stream<Arguments> detectsJoinAliasesCorrectlySource() {
893931

894932
return Stream.of( //

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

+15
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* @author JyotirmoyVS
5656
* @author Greg Turnquist
5757
* @author Simon Paradies
58+
* @author Diego Krupitza
5859
*/
5960
public interface UserRepository
6061
extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User>, UserRepositoryCustom {
@@ -676,6 +677,20 @@ List<String> findAllAndSortByFunctionResultNamedParameter(@Param("namedParameter
676677
nativeQuery = true)
677678
List<String> complexWithNativeStatement();
678679

680+
// GH-2593
681+
@Modifying
682+
@Query(
683+
value = "INSERT INTO SD_User(id,active,age,firstname,lastname,emailAddress,DTYPE) VALUES (9999,true,23,'Diego','K','[email protected]','User')",
684+
nativeQuery = true)
685+
void insertNewUserWithNativeQuery();
686+
687+
// GH-2593
688+
@Modifying
689+
@Query(
690+
value = "INSERT INTO SD_User(id,active,age,firstname,lastname,emailAddress,DTYPE) VALUES (9999,true,23,'Diego',:lastname,'[email protected]','User')",
691+
nativeQuery = true)
692+
void insertNewUserWithParamNativeQuery(@Param("lastname") String lastname);
693+
679694
interface RolesAndFirstname {
680695

681696
String getFirstname();

0 commit comments

Comments
 (0)