Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SELECT FOR UPDATE method matching in raw queries #3249

Merged
merged 6 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public BookRepository(AuthorRepository authorRepository) {
super(authorRepository);
}

@Override
public abstract Book save(Book book);

/**
* @deprecated Order by 'author.name' case without a join. Hibernate will do the cross join if the association property is accessed by the property path without join.
*/
Expand Down Expand Up @@ -71,7 +74,7 @@ public BookRepository(AuthorRepository authorRepository) {
@Query(value = "select count(*) from book b where b.title like :title and b.total_pages > :pages", nativeQuery = true)
abstract int countNativeByTitleWithPagesGreaterThan(String title, int pages);

@Query(value = "select * from book where (CASE WHEN CAST(:arg0 AS VARCHAR) is not null THEN title = :arg0 ELSE true END)", nativeQuery = true)
@Query(value = "select * from book where (CASE WHEN CAST(:arg0 AS VARCHAR) is not null THEN title = :arg0 ELSE true END) FOR UPDATE", nativeQuery = true)
public abstract List<Book> listNativeBooksNullableSearch(@Nullable String arg0);

@Query(value = "select * from book where (CASE WHEN exists ( select (:arg0) ) THEN title IN (:arg0) ELSE true END)", nativeQuery = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
public class RawQueryMethodMatcher implements MethodMatcher {

private static final Pattern UPDATE_PATTERN = Pattern.compile(".*\\bupdate\\b.*");
private static final Pattern FOR_UPDATE_PATTERN = Pattern.compile("for\\s+update");
private static final Pattern DELETE_PATTERN = Pattern.compile(".*\\bdelete\\b.*");
private static final Pattern INSERT_PATTERN = Pattern.compile(".*\\binsert\\b.*");
private static final Pattern RETURNING_PATTERN = Pattern.compile(".*\\breturning\\b.*");
Expand Down Expand Up @@ -185,7 +186,9 @@ private DataMethod.OperationType findOperationType(String methodName, String que
if (DeleteMethodMatcher.METHOD_PATTERN.matcher(methodName.toLowerCase(Locale.ENGLISH)).matches()) {
return DataMethod.OperationType.DELETE;
}
return DataMethod.OperationType.UPDATE;
if (!FOR_UPDATE_PATTERN.matcher(query).find()) {
return DataMethod.OperationType.UPDATE;
}
} else if (INSERT_PATTERN.matcher(query).find()) {
if (RETURNING_PATTERN.matcher(query).find()) {
return DataMethod.OperationType.INSERT_RETURNING;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2088,7 +2088,7 @@ import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.tck.entities.Person;

@JdbcRepository(dialect= Dialect.MYSQL)
@JdbcRepository(dialect = Dialect.MYSQL)
@io.micronaut.context.annotation.Executable
interface PersonRepository extends CrudRepository<Person, Long> {

Expand All @@ -2098,14 +2098,25 @@ interface PersonRepository extends CrudRepository<Person, Long> {
\""")
$type customSelect(Long id);

@Query(\"""
SELECT * FROM person WHERE id = :id FOR
UPDATE
\""")
$type selectForUpdate(Long id);

}
""")
def method = repository.findPossibleMethods("customSelect").findFirst().get()
def selectQuery = getQuery(method)
def customSelectMethod = repository.findPossibleMethods("customSelect").findFirst().get()
def customSelectQuery = getQuery(customSelectMethod)
def selectForUpdateMethod = repository.findPossibleMethods("selectForUpdate").findFirst().get()
def selectForUpdateQuery = getQuery(selectForUpdateMethod)

expect:
selectQuery.replace('\n', ' ') == "WITH ids AS (SELECT id FROM person) SELECT * FROM person "
method.classValue(DataMethod, "interceptor").get() == interceptor
customSelectQuery.replace('\n', ' ') == "WITH ids AS (SELECT id FROM person) SELECT * FROM person "
customSelectMethod.classValue(DataMethod, "interceptor").get() == interceptor

selectForUpdateQuery.replace('\n', ' ') == "SELECT * FROM person WHERE id = :id FOR UPDATE "
selectForUpdateMethod.classValue(DataMethod, "interceptor").get() == interceptor

where:
type | interceptor
Expand Down
Loading