Made JSqlParserQueryEnhancer aware of MERGE statements.

Closes #2641.
This commit is contained in:
Geoffrey Deremetz
2022-09-23 16:50:51 +02:00
committed by Greg L. Turnquist
parent eff3803594
commit e589265eba
4 changed files with 47 additions and 1 deletions

View File

@@ -28,6 +28,7 @@ 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.merge.Merge;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
@@ -58,6 +59,7 @@ import org.springframework.util.StringUtils;
*
* @author Diego Krupitza
* @author Greg Turnquist
* @author Geoffrey Deremetz
* @since 2.7.0
*/
public class JSqlParserQueryEnhancer implements QueryEnhancer {
@@ -92,6 +94,8 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
return ParsedType.DELETE;
} else if (statement instanceof Select) {
return ParsedType.SELECT;
} else if (statement instanceof Merge) {
return ParsedType.MERGE;
} else {
return ParsedType.SELECT;
}
@@ -483,10 +487,11 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
* <li>{@code ParsedType.UPDATE}: means the top level statement is {@link Update}</li>
* <li>{@code ParsedType.SELECT}: means the top level statement is {@link Select}</li>
* <li>{@code ParsedType.INSERT}: means the top level statement is {@link Insert}</li>
* <li>{@code ParsedType.MERGE}: means the top level statement is {@link Merge}</li>
* </ul>
*/
enum ParsedType {
DELETE, UPDATE, SELECT, INSERT;
DELETE, UPDATE, SELECT, INSERT, MERGE;
}
}

View File

@@ -107,6 +107,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author Diego Krupitza
* @author Daniel Shuy
* @author Simon Paradies
* @author Geoffrey Deremetz
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:application-context.xml")
@@ -2810,6 +2811,22 @@ public class UserRepositoryTests {
.contains("Gierke", "Arrasz", "Matthews", "raymond", testLastName);
}
@Test // GH-2641
void mergeWithNativeStatement() {
flushTestUsers();
Optional<User> byIdUser = repository.findById(firstUser.getId());
assertThat(byIdUser).isPresent().map(User::getAge).get().isEqualTo(28);
// when
repository.mergeNativeStatement();
// then
Optional<User> afterUpdate = repository.findById(firstUser.getId());
assertThat(afterUpdate).isPresent().map(User::getAge).get().isEqualTo(30);
}
private Page<User> executeSpecWithSort(Sort sort) {
flushTestUsers();

View File

@@ -38,6 +38,7 @@ import org.springframework.data.jpa.domain.JpaSort;
* Unit tests for {@link QueryEnhancer}.
*
* @author Diego Krupitza
* @author Geoffrey Deremetz
*/
class QueryEnhancerUnitTests {
@@ -922,6 +923,18 @@ class QueryEnhancerUnitTests {
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
}
@Test // GH-2641
void mergeStatementWorksWithJSqlParser() {
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";
StringQuery stringQuery = new StringQuery(query, true);
QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
assertThat(queryEnhancer.getJoinAliases()).isEmpty();
assertThat(queryEnhancer.detectAlias()).isNull();
assertThat(queryEnhancer.getProjection()).isEmpty();
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
}
public static Stream<Arguments> insertStatementIsProcessedSameAsDefaultSource() {
return Stream.of( //
Arguments.of("INSERT INTO FOO(A) VALUES('A')"), //

View File

@@ -55,6 +55,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author Greg Turnquist
* @author Simon Paradies
* @author Diego Krupitza
* @author Geoffrey Deremetz
*/
public interface UserRepository
extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User>, UserRepositoryCustom {
@@ -693,6 +694,16 @@ public interface UserRepository
nativeQuery = true)
void insertNewUserWithParamNativeQuery(@Param("lastname") String lastname);
// GH-2641
@Modifying(clearAutomatically = true)
@Query(value = "merge into sd_user " + //
"using (select id from sd_user where age < 30) request " + //
"on (sd_user.id = request.id) " + //
"when matched then " + //
" update set sd_user.age = 30", //
nativeQuery = true)
int mergeNativeStatement();
interface RolesAndFirstname {
String getFirstname();