Polishing.

Ensure ordering of the last query only, applying ordering after the set operation.

Original pull request: #3429
See #3427
This commit is contained in:
Mark Paluch
2024-08-02 10:20:33 +02:00
parent b02081b439
commit 3191b88e82
4 changed files with 35 additions and 36 deletions

View File

@@ -47,10 +47,10 @@ class HqlSortedQueryTransformer extends HqlQueryRenderer {
this.primaryFromAlias = primaryFromAlias;
}
@Override
public QueryTokenStream visitQueryExpression(HqlParser.QueryExpressionContext ctx) {
if(ObjectUtils.isEmpty(ctx.setOperator())) {
if (ObjectUtils.isEmpty(ctx.setOperator())) {
return super.visitQueryExpression(ctx);
}
@@ -59,15 +59,20 @@ class HqlSortedQueryTransformer extends HqlQueryRenderer {
builder.appendExpression(visit(ctx.withClause()));
}
builder.append(visitOrderedQuery(ctx.orderedQuery(0), Sort.unsorted()));
List<HqlParser.OrderedQueryContext> orderedQueries = ctx.orderedQuery();
for (int i = 0; i < orderedQueries.size(); i++) {
for (int i = 1; i < ctx.orderedQuery().size(); i++) {
if (i != 0) {
builder.append(visit(ctx.setOperator(i - 1)));
}
builder.append(visit(ctx.setOperator(i - 1)));
builder.append(visit(ctx.orderedQuery(i)));
if (i == orderedQueries.size() - 1) {
builder.append(visitOrderedQuery(ctx.orderedQuery(i), this.sort));
} else {
builder.append(visitOrderedQuery(ctx.orderedQuery(i), Sort.unsorted()));
}
}
return builder;
}
@@ -81,7 +86,7 @@ class HqlSortedQueryTransformer extends HqlQueryRenderer {
QueryTokenStream tokens = super.visitJoinPath(ctx);
if (ctx.variable() != null && !isSubquery(ctx)) {
if (ctx.variable() != null && !isSubquery(ctx)) {
transformerSupport.registerAlias(tokens.getLast());
}
@@ -93,7 +98,7 @@ class HqlSortedQueryTransformer extends HqlQueryRenderer {
QueryTokenStream tokens = super.visitJoinSubquery(ctx);
if (ctx.variable() != null && !tokens.isEmpty() && !isSubquery(ctx)) {
if (ctx.variable() != null && !tokens.isEmpty() && !isSubquery(ctx)) {
transformerSupport.registerAlias(tokens.getLast());
}
@@ -105,7 +110,7 @@ class HqlSortedQueryTransformer extends HqlQueryRenderer {
QueryTokenStream tokens = super.visitVariable(ctx);
if (ctx.identifier() != null && !tokens.isEmpty() && !isSubquery(ctx)) {
if (ctx.identifier() != null && !tokens.isEmpty() && !isSubquery(ctx)) {
transformerSupport.registerAlias(tokens.getLast());
}

View File

@@ -98,7 +98,7 @@ class EqlQueryTransformerTests {
}
@Test
void applyCountToAlreadySorteQuery() {
void applyCountToAlreadySortedQuery() {
// given
var original = "SELECT e FROM Employee e where e.name = :name ORDER BY e.modified_date";
@@ -762,10 +762,12 @@ class EqlQueryTransformerTests {
@Test // GH-3427
void sortShouldBeAppendedToFullSelectOnlyInCaseOfSetOperator() {
String source = "SELECT tb FROM Test tb WHERE (tb.type='A') UNION SELECT tb FROM Test tb WHERE (tb.type='B')";
String source = "SELECT tb FROM Test tb WHERE (tb.type='A') UNION SELECT tb FROM Test tb WHERE (tb.type='B') UNION SELECT tb FROM Test tb WHERE (tb.type='C')";
String target = createQueryFor(source, Sort.by("Type").ascending());
assertThat(target).isEqualTo("SELECT tb FROM Test tb WHERE (tb.type = 'A') UNION SELECT tb FROM Test tb WHERE (tb.type = 'B') order by tb.Type asc");
assertThat(target).isEqualTo("SELECT tb FROM Test tb WHERE (tb.type = 'A') " //
+ "UNION SELECT tb FROM Test tb WHERE (tb.type = 'B') " //
+ "UNION SELECT tb FROM Test tb WHERE (tb.type = 'C') order by tb.Type asc");
}
static Stream<Arguments> queriesWithReservedWordsAsIdentifiers() {

View File

@@ -705,11 +705,9 @@ class HqlQueryTransformerTests {
.isEqualTo("select dense_rank() over (order by lastname) from user u order by u.lastname, u.age desc");
// partition by + order by in over clause
assertThat(
createQueryFor(
"select dense_rank() over (partition by active, age order by lastname range between 1.0 preceding and 1.0 following) from user u",
sort))
.isEqualTo(
assertThat(createQueryFor(
"select dense_rank() over (partition by active, age order by lastname range between 1.0 preceding and 1.0 following) from user u",
sort)).isEqualTo(
"select dense_rank() over (partition by active, age order by lastname range between 1.0 preceding and 1.0 following) from user u order by u.age desc");
// partition by + order by in over clause + order by at the end
@@ -1068,19 +1066,23 @@ class HqlQueryTransformerTests {
@Test // GH-3427
void sortShouldBeAppendedWithSpacingInCaseOfSetOperator() {
String source = "SELECT tb FROM Test tb WHERE (tb.type='A') UNION SELECT tb FROM Test tb WHERE (tb.type='B')";
String source = "SELECT tb FROM Test tb WHERE (tb.type='A') UNION SELECT tb FROM Test tb WHERE (tb.type='B') UNION SELECT tb FROM Test tb WHERE (tb.type='C')";
String target = createQueryFor(source, Sort.by("Type").ascending());
assertThat(target).isEqualTo("SELECT tb FROM Test tb WHERE (tb.type = 'A') UNION SELECT tb FROM Test tb WHERE (tb.type = 'B') order by tb.Type asc");
assertThat(target).isEqualTo("SELECT tb FROM Test tb WHERE (tb.type = 'A') " //
+ "UNION SELECT tb FROM Test tb WHERE (tb.type = 'B') " //
+ "UNION SELECT tb FROM Test tb WHERE (tb.type = 'C') order by tb.Type asc");
}
@ParameterizedTest // GH-3427
@ValueSource(strings = {"", "res"})
@ValueSource(strings = { "", "res" })
void sortShouldBeAppendedToSubSelectWithSetOperatorInSubselect(String alias) {
String prefix = StringUtils.hasText(alias) ? (alias + ".") : "";
String source = "SELECT %sname FROM (SELECT c.name as name FROM Category c UNION SELECT t.name as name FROM Tag t)".formatted(prefix);
if(StringUtils.hasText(alias)) {
String source = "SELECT %sname FROM (SELECT c.name as name FROM Category c UNION SELECT t.name as name FROM Tag t)"
.formatted(prefix);
if (StringUtils.hasText(alias)) {
source = source + " %s".formatted(alias);
}
@@ -1088,10 +1090,10 @@ class HqlQueryTransformerTests {
assertThat(target).contains(" UNION SELECT ").doesNotContainPattern(Pattern.compile(".*\\SUNION"));
assertThat(target).endsWith("order by %sname asc".formatted(prefix)).satisfies(it -> {
Pattern pattern = Pattern.compile("order by %sname".formatted(prefix));
Pattern pattern = Pattern.compile("order by");
Matcher matcher = pattern.matcher(target);
int count = 0;
while(matcher.find()) {
while (matcher.find()) {
count++;
}
assertThat(count).describedAs("Found order by clause more than once in: \n%s", it).isOne();

View File

@@ -198,16 +198,6 @@ class JpqlQueryTransformerTests {
Sort sort = Sort.by(Sort.Order.desc("age"));
//
//
//
//
//
//
//
//
//
//
assertThat(newParser("""
select u
from user u