@@ -433,6 +433,7 @@ public abstract class QueryUtils {
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public static String detectAlias(String query) {
|
||||
|
||||
String alias = null;
|
||||
Matcher matcher = ALIAS_MATCH.matcher(removeSubqueries(query));
|
||||
while (matcher.find()) {
|
||||
@@ -442,23 +443,25 @@ public abstract class QueryUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove subqueries from the query, in order to identify the correct alias
|
||||
* in order by clauses. If the entire query is surrounded by parenthesis, the
|
||||
* outermost parenthesis are not removed.
|
||||
* Remove subqueries from the query, in order to identify the correct alias in order by clauses. If the entire query
|
||||
* is surrounded by parenthesis, the outermost parenthesis are not removed.
|
||||
*
|
||||
* @param query
|
||||
* @return query with all subqueries removed.
|
||||
*/
|
||||
static String removeSubqueries(String query) {
|
||||
|
||||
if (!StringUtils.hasText(query)) {
|
||||
return query;
|
||||
}
|
||||
|
||||
final List<Integer> opens = new ArrayList<>();
|
||||
final List<Integer> closes = new ArrayList<>();
|
||||
final List<Boolean> closeMatches = new ArrayList<>();
|
||||
for (int i=0; i<query.length(); i++) {
|
||||
final char c = query.charAt(i);
|
||||
List<Integer> opens = new ArrayList<>();
|
||||
List<Integer> closes = new ArrayList<>();
|
||||
List<Boolean> closeMatches = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < query.length(); i++) {
|
||||
|
||||
char c = query.charAt(i);
|
||||
if (c == '(') {
|
||||
opens.add(i);
|
||||
} else if (c == ')') {
|
||||
@@ -467,18 +470,19 @@ public abstract class QueryUtils {
|
||||
}
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder(query);
|
||||
final boolean startsWithParen = STARTS_WITH_PAREN.matcher(query).find();
|
||||
for (int i=opens.size()-1; i>=(startsWithParen?1:0); i--) {
|
||||
final Integer open = opens.get(i);
|
||||
final Integer close = findClose(open, closes, closeMatches) + 1;
|
||||
StringBuilder sb = new StringBuilder(query);
|
||||
boolean startsWithParen = STARTS_WITH_PAREN.matcher(query).find();
|
||||
for (int i = opens.size() - 1; i >= (startsWithParen ? 1 : 0); i--) {
|
||||
|
||||
Integer open = opens.get(i);
|
||||
Integer close = findClose(open, closes, closeMatches) + 1;
|
||||
|
||||
if (close > open) {
|
||||
final String subquery = sb.substring(open, close);
|
||||
final Matcher matcher = PARENS_TO_REMOVE.matcher(subquery);
|
||||
|
||||
String subquery = sb.substring(open, close);
|
||||
Matcher matcher = PARENS_TO_REMOVE.matcher(subquery);
|
||||
if (matcher.find()) {
|
||||
sb.replace(open, close, new String(new char[close-open]).replace('\0', ' '));
|
||||
sb.replace(open, close, new String(new char[close - open]).replace('\0', ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,8 +491,10 @@ public abstract class QueryUtils {
|
||||
}
|
||||
|
||||
private static Integer findClose(final Integer open, final List<Integer> closes, final List<Boolean> closeMatches) {
|
||||
for (int i=0; i<closes.size(); i++) {
|
||||
final int close = closes.get(i);
|
||||
|
||||
for (int i = 0; i < closes.size(); i++) {
|
||||
|
||||
int close = closes.get(i);
|
||||
if (close > open && !closeMatches.get(i)) {
|
||||
closeMatches.set(i, Boolean.TRUE);
|
||||
return close;
|
||||
@@ -594,7 +600,7 @@ public abstract class QueryUtils {
|
||||
String replacement = useVariable ? SIMPLE_COUNT_VALUE : complexCountValue;
|
||||
|
||||
String alias = QueryUtils.detectAlias(originalQuery);
|
||||
if("*".equals(variable) && alias != null) {
|
||||
if ("*".equals(variable) && alias != null) {
|
||||
replacement = alias;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,13 +120,19 @@ class QueryUtilsUnitTests {
|
||||
assertThat(detectAlias("select u from T05User u")).isEqualTo("u");
|
||||
assertThat(detectAlias("select u from User u where not exists (from User u2)")).isEqualTo("u");
|
||||
assertThat(detectAlias("(select u from User u where not exists (from User u2))")).isEqualTo("u");
|
||||
assertThat(detectAlias("(select u from User u where not exists ((from User u2 where not exists (from User u3))))")).isEqualTo("u");
|
||||
assertThat(detectAlias("from Foo f left join f.bar b with type(b) = BarChild where (f.id = (select max(f.id) from Foo f2 where type(f2) = FooChild) or 1 <> 1) and 1=1")).isEqualTo("f");
|
||||
assertThat(detectAlias("(from Foo f max(f) ((((select * from Foo f2 (from Foo f3) max(*)) (from Foo f4)) max(f5)) (f6)) (from Foo f7))")).isEqualTo("f");
|
||||
assertThat(detectAlias("(select u from User u where not exists ((from User u2 where not exists (from User u3))))"))
|
||||
.isEqualTo("u");
|
||||
assertThat(detectAlias(
|
||||
"from Foo f left join f.bar b with type(b) = BarChild where (f.id = (select max(f.id) from Foo f2 where type(f2) = FooChild) or 1 <> 1) and 1=1"))
|
||||
.isEqualTo("f");
|
||||
assertThat(detectAlias(
|
||||
"(from Foo f max(f) ((((select * from Foo f2 (from Foo f3) max(*)) (from Foo f4)) max(f5)) (f6)) (from Foo f7))"))
|
||||
.isEqualTo("f");
|
||||
}
|
||||
|
||||
@Test // GH-2260
|
||||
void testRemoveSubqueries() throws Exception {
|
||||
|
||||
// boundary conditions
|
||||
assertThat(removeSubqueries(null)).isNull();
|
||||
assertThat(removeSubqueries("")).isEmpty();
|
||||
@@ -145,11 +151,19 @@ class QueryUtilsUnitTests {
|
||||
assertThat(removeSubqueries("select u from User u")).isEqualTo("select u from User u");
|
||||
assertThat(removeSubqueries("select u from com.acme.User u")).isEqualTo("select u from com.acme.User u");
|
||||
assertThat(removeSubqueries("select u from T05User u")).isEqualTo("select u from T05User u");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("select u from User u where not exists (from User u2)"))).isEqualTo("select u from User u where not exists");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("(select u from User u where not exists (from User u2))"))).isEqualTo("(select u from User u where not exists )");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("select u from User u where not exists (from User u2 where not exists (from User u3))"))).isEqualTo("select u from User u where not exists");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("select u from User u where not exists ((from User u2 where not exists (from User u3)))"))).isEqualTo("select u from User u where not exists ( )");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("(select u from User u where not exists ((from User u2 where not exists (from User u3))))"))).isEqualTo("(select u from User u where not exists ( ))");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("select u from User u where not exists (from User u2)")))
|
||||
.isEqualTo("select u from User u where not exists");
|
||||
assertThat(normalizeWhitespace(removeSubqueries("(select u from User u where not exists (from User u2))")))
|
||||
.isEqualTo("(select u from User u where not exists )");
|
||||
assertThat(normalizeWhitespace(
|
||||
removeSubqueries("select u from User u where not exists (from User u2 where not exists (from User u3))")))
|
||||
.isEqualTo("select u from User u where not exists");
|
||||
assertThat(normalizeWhitespace(
|
||||
removeSubqueries("select u from User u where not exists ((from User u2 where not exists (from User u3)))")))
|
||||
.isEqualTo("select u from User u where not exists ( )");
|
||||
assertThat(normalizeWhitespace(
|
||||
removeSubqueries("(select u from User u where not exists ((from User u2 where not exists (from User u3))))")))
|
||||
.isEqualTo("(select u from User u where not exists ( ))");
|
||||
}
|
||||
|
||||
private String normalizeWhitespace(String s) {
|
||||
@@ -690,16 +704,21 @@ class QueryUtilsUnitTests {
|
||||
String countQueryFor = createCountQueryFor("SELECT * FROM User WHERE created_at > $1");
|
||||
assertThat(countQueryFor).isEqualTo("select count(*) FROM User WHERE created_at > $1");
|
||||
|
||||
countQueryFor = createCountQueryFor("SELECT * FROM mytable WHERE nr = :number AND kon = :kon AND datum >= '2019-01-01'");
|
||||
assertThat(countQueryFor).isEqualTo("select count(*) FROM mytable WHERE nr = :number AND kon = :kon AND datum >= '2019-01-01'");
|
||||
countQueryFor = createCountQueryFor(
|
||||
"SELECT * FROM mytable WHERE nr = :number AND kon = :kon AND datum >= '2019-01-01'");
|
||||
assertThat(countQueryFor)
|
||||
.isEqualTo("select count(*) FROM mytable WHERE nr = :number AND kon = :kon AND datum >= '2019-01-01'");
|
||||
|
||||
countQueryFor = createCountQueryFor("SELECT * FROM context ORDER BY time");
|
||||
assertThat(countQueryFor).isEqualTo("select count(*) FROM context");
|
||||
|
||||
countQueryFor = createCountQueryFor("select * FROM users_statuses WHERE (user_created_at BETWEEN $1 AND $2)");
|
||||
assertThat(countQueryFor).isEqualTo("select count(*) FROM users_statuses WHERE (user_created_at BETWEEN $1 AND $2)");
|
||||
assertThat(countQueryFor)
|
||||
.isEqualTo("select count(*) FROM users_statuses WHERE (user_created_at BETWEEN $1 AND $2)");
|
||||
|
||||
countQueryFor = createCountQueryFor("SELECT * FROM users_statuses us WHERE (user_created_at BETWEEN :fromDate AND :toDate)");
|
||||
assertThat(countQueryFor).isEqualTo("select count(us) FROM users_statuses us WHERE (user_created_at BETWEEN :fromDate AND :toDate)");
|
||||
countQueryFor = createCountQueryFor(
|
||||
"SELECT * FROM users_statuses us WHERE (user_created_at BETWEEN :fromDate AND :toDate)");
|
||||
assertThat(countQueryFor)
|
||||
.isEqualTo("select count(us) FROM users_statuses us WHERE (user_created_at BETWEEN :fromDate AND :toDate)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user