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 order by rendering for queries containing UNION #3429

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

christophstrobl
Copy link
Member

Make sure to append space after order by clause and fix alias detection for wrapped sub select.
Also make sure to ignore alias used in subselect so they do not conflict with root ones.

Closes: #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 target = createQueryFor(source, Sort.by("Type").ascending());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this line target has the value

SELECT tb 
    FROM Test tb 
    WHERE (tb.type = 'A') 
    order by tb.Type asc 
UNION 
SELECT tb 
    FROM Test tb 
    WHERE (tb.type = 'B') 
    order by tb.Type asc`

i.e. the order by is applied twice which is illegal, since according to answers here https://stackoverflow.com/questions/4715820/how-to-order-by-with-union-in-sql the later order by applies to the full union and an order by on the individual selects might be even illegal (probably depends on the database)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we do not know the target db nor how it handles order by we cannot imply ordering the last is the correct behaviour, nor do we have the means to define which of the selects to decorate. an alternative would be to raise an error and demand wrapping the entire thing as it's done in one of the follow up tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, let's wait and see what kind of reports we get. We can then still react to the feedback we receive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reading through IBM an Oracle SQL reference docs @schauder has a good point in the above mentioned query not being compliant (at least not in the form it is currently rendered)

For example, the following is not valid (SQLSTATE 428FJ):
SELECT * FROM T1
ORDER BY C1
UNION
SELECT * FROM T2
ORDER BY C1

The following example is valid:
(SELECT * FROM T1
ORDER BY C1)
UNION
(SELECT * FROM T2
ORDER BY C1)

String source = "SELECT tb FROM Test tb WHERE (tb.type='A') UNION SELECT tb FROM Test tb WHERE (tb.type='B')";
String target = createQueryFor(source, Sort.by("Type").ascending());

assertThat(target).contains(" UNION SELECT ").doesNotContainPattern(Pattern.compile(".*\\SUNION"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we put in an exact SQL statement we should be able to assert on a precise output and not rely on pattern matching and simiar.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems legit

}

@ParameterizedTest // GH-3427
@ValueSource(strings = {"", "res"})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment would be nice explaining why we need to run this with different prefixes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deemed to be obvious - apparently isn't

@ValueSource(strings = {"", "res"})
void sortShouldBeAppendedToSubSelectWithSetOperatorInSubselect(String alias) {

String prefix = StringUtils.hasText(alias) ? (alias + ".") : "";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I think we should be able to and prefer a simple equals-assertion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of duplication.

@christophstrobl
Copy link
Member Author

we should additionally check the count query creation for UNION.

Make sure to append space after order by clause and fix alias detection for wrapped sub select.
Also make sure to ignore alias used in subselect so they do not conflict with root ones.
@christophstrobl
Copy link
Member Author

@schauder @mp911de - care to have another look at this one.
Changed the sort transformation so that the provided Sort is now appended after the last query expression.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Spring Data JPA generates incorrect JPQL query for sorted pagination request with UNION clause
3 participants