diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java
index 1c6c42ae8..4b5d64fc5 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java
@@ -26,6 +26,7 @@ import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
+import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
@@ -82,7 +83,9 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
try {
Statement statement = CCJSqlParserUtil.parse(this.query.getQueryString());
- if (statement instanceof Update) {
+ if (statement instanceof Insert) {
+ return ParsedType.INSERT;
+ } else if (statement instanceof Update) {
return ParsedType.UPDATE;
} else if (statement instanceof Delete) {
return ParsedType.DELETE;
@@ -475,10 +478,11 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
*
{@code ParsedType.DELETE}: means the top level statement is {@link Delete}
* {@code ParsedType.UPDATE}: means the top level statement is {@link Update}
* {@code ParsedType.SELECT}: means the top level statement is {@link Select}
+ * {@code ParsedType.INSERT}: means the top level statement is {@link Insert}
*
*/
enum ParsedType {
- DELETE, UPDATE, SELECT;
+ DELETE, UPDATE, SELECT, INSERT;
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
index 283e45161..4f88fe896 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
@@ -15,13 +15,14 @@
*/
package org.springframework.data.jpa.repository;
-import static java.util.Arrays.*;
+import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.*;
-import static org.springframework.data.domain.Example.*;
+import static org.springframework.data.domain.Example.of;
import static org.springframework.data.domain.ExampleMatcher.*;
-import static org.springframework.data.domain.Sort.Direction.*;
-import static org.springframework.data.jpa.domain.Specification.*;
+import static org.springframework.data.domain.Sort.Direction.ASC;
+import static org.springframework.data.domain.Sort.Direction.DESC;
import static org.springframework.data.jpa.domain.Specification.not;
+import static org.springframework.data.jpa.domain.Specification.where;
import static org.springframework.data.jpa.domain.sample.UserSpecifications.*;
import jakarta.persistence.EntityManager;
@@ -33,14 +34,7 @@ import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import lombok.Data;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
import java.util.stream.Stream;
import org.assertj.core.api.SoftAssertions;
@@ -54,14 +48,7 @@ import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
-import org.springframework.data.domain.Example;
-import org.springframework.data.domain.ExampleMatcher;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Slice;
-import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.*;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
@@ -2969,7 +2956,7 @@ public class UserRepositoryTests {
}
@Test // GH-2607
- void containsWithCollection(){
+ void containsWithCollection() {
firstUser.getAttributes().add("cool");
firstUser.getAttributes().add("hip");
@@ -2986,6 +2973,35 @@ public class UserRepositoryTests {
assertThat(result).containsOnly(firstUser, secondUser);
}
+ @Test // GH-2593
+ void insertStatementModifyingQueryWorks() {
+ flushTestUsers();
+ repository.insertNewUserWithNativeQuery();
+
+ List all = repository.findAll();
+ assertThat(all) //
+ .isNotNull() //
+ .isNotEmpty() //
+ .hasSize(5) //
+ .map(User::getLastname) //
+ .contains("Gierke", "Arrasz", "Matthews", "raymond", "K");
+ }
+
+ @Test // GH-2593
+ void insertStatementModifyingQueryWithParamsWorks() {
+ flushTestUsers();
+ String testLastName = "TestLastName";
+ repository.insertNewUserWithParamNativeQuery(testLastName);
+
+ List all = repository.findAll();
+ assertThat(all) //
+ .isNotNull() //
+ .isNotEmpty() //
+ .hasSize(5) //
+ .map(User::getLastname) //
+ .contains("Gierke", "Arrasz", "Matthews", "raymond", testLastName);
+ }
+
private Page executeSpecWithSort(Sort sort) {
flushTestUsers();
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
index c87946863..bc9f20010 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
@@ -889,6 +889,44 @@ class QueryEnhancerUnitTests {
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
}
+ @ParameterizedTest // GH-2593
+ @MethodSource("insertStatementIsProcessedSameAsDefaultSource")
+ void insertStatementIsProcessedSameAsDefault(String insertQuery) {
+
+ StringQuery stringQuery = new StringQuery(insertQuery, true);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+
+ Sort sorting = Sort.by("day").descending();
+
+ // queryutils results
+ String queryUtilsDetectAlias = QueryUtils.detectAlias(insertQuery);
+ String queryUtilsProjection = QueryUtils.getProjection(insertQuery);
+ String queryUtilsCountQuery = QueryUtils.createCountQueryFor(insertQuery);
+ Set queryUtilsOuterJoinAlias = QueryUtils.getOuterJoinAliases(insertQuery);
+
+ // direct access
+ assertThat(stringQuery.getAlias()).isEqualToIgnoringCase(queryUtilsDetectAlias);
+ assertThat(stringQuery.getProjection()).isEqualToIgnoringCase(queryUtilsProjection);
+ assertThat(stringQuery.hasConstructorExpression()).isFalse();
+
+ // access over enhancer
+ assertThat(queryEnhancer.createCountQueryFor()).isEqualToIgnoringCase(queryUtilsCountQuery);
+ assertThat(queryEnhancer.applySorting(sorting)).isEqualTo(insertQuery); // cant check with queryutils result since
+ // query utils appens order by which is not
+ // supported by sql standard.
+ assertThat(queryEnhancer.getJoinAliases()).isEqualTo(queryUtilsOuterJoinAlias);
+ assertThat(queryEnhancer.detectAlias()).isEqualToIgnoringCase(queryUtilsDetectAlias);
+ assertThat(queryEnhancer.getProjection()).isEqualToIgnoringCase(queryUtilsProjection);
+ assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
+ }
+
+ public static Stream insertStatementIsProcessedSameAsDefaultSource() {
+ return Stream.of( //
+ Arguments.of("INSERT INTO FOO(A) VALUES('A')"), //
+ Arguments.of("INSERT INTO randomsecondTable(A,B,C,D) VALUES('A','B','C','D')") //
+ );
+ }
+
public static Stream detectsJoinAliasesCorrectlySource() {
return Stream.of( //
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
index 3236ddfa3..b7bd9b5b9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
@@ -18,27 +18,14 @@ package org.springframework.data.jpa.repository.sample;
import jakarta.persistence.EntityManager;
import jakarta.persistence.QueryHint;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
import java.util.stream.Stream;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Slice;
-import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.domain.sample.SpecialUser;
import org.springframework.data.jpa.domain.sample.User;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-import org.springframework.data.jpa.repository.Modifying;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.jpa.repository.QueryHints;
+import org.springframework.data.jpa.repository.*;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
@@ -55,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author JyotirmoyVS
* @author Greg Turnquist
* @author Simon Paradies
+ * @author Diego Krupitza
*/
public interface UserRepository
extends JpaRepository, JpaSpecificationExecutor, UserRepositoryCustom {
@@ -679,6 +667,20 @@ public interface UserRepository
// GH-2607
List findByAttributesContains(String attribute);
+ // GH-2593
+ @Modifying
+ @Query(
+ value = "INSERT INTO SD_User(id,active,age,firstname,lastname,emailAddress,DTYPE) VALUES (9999,true,23,'Diego','K','dk@email.com','User')",
+ nativeQuery = true)
+ void insertNewUserWithNativeQuery();
+
+ // GH-2593
+ @Modifying
+ @Query(
+ value = "INSERT INTO SD_User(id,active,age,firstname,lastname,emailAddress,DTYPE) VALUES (9999,true,23,'Diego',:lastname,'dk@email.com','User')",
+ nativeQuery = true)
+ void insertNewUserWithParamNativeQuery(@Param("lastname") String lastname);
+
interface RolesAndFirstname {
String getFirstname();