blob: 74bc4f114f432f71507497785a41e9285f6af32a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.cache.query.internal;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.apache.geode.cache.query.QueryInvalidException;
import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes;
import org.apache.geode.cache.query.security.MethodInvocationAuthorizer;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.test.junit.categories.OQLQueryTest;
@Category(OQLQueryTest.class)
@RunWith(JUnitParamsRunner.class)
public class QCompilerTest {
private QueryExecutionContext context;
@Before
public void setUp() {
InternalCache mockCache = mock(InternalCache.class);
when(mockCache.getQueryService()).thenReturn(mock(InternalQueryService.class));
when(mockCache.getQueryService().getMethodInvocationAuthorizer())
.thenReturn(mock(MethodInvocationAuthorizer.class));
context = new QueryExecutionContext(null, mockCache);
}
@Test
public void testStringConditioningForLike_1() {
String s1 = "abc%";
StringBuffer buffer = new StringBuffer(s1);
CompiledLike cl = new CompiledLike(null, null);
int wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(3);
assertThat(buffer.toString()).isEqualTo(s1);
s1 = "abc\\%abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(-1);
assertThat(buffer.toString()).isEqualTo("abc%abc");
s1 = "abc\\\\%abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(4);
assertThat(buffer.toString()).isEqualTo("abc\\%abc");
s1 = "abc\\\\\\%abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(-1);
assertThat(buffer.toString()).isEqualTo("abc\\%abc");
s1 = "%";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(0);
assertThat(buffer.toString()).isEqualTo(s1);
s1 = "%abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(0);
assertThat(buffer.toString()).isEqualTo("%abc");
s1 = "%%abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(0);
assertThat(buffer.toString()).isEqualTo("%%abc");
s1 = "%\\%abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(0);
assertThat(buffer.toString()).isEqualTo("%\\%abc");
s1 = "_abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(0);
assertThat(buffer.toString()).isEqualTo("_abc");
s1 = "\\_abc";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(-1);
assertThat(buffer.toString()).isEqualTo("_abc");
s1 = "ab\\%c%d";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(4);
assertThat(buffer.toString()).isEqualTo("ab%c%d");
s1 = "ab\\__d";
buffer = new StringBuffer(s1);
wildCardPosition = cl.checkIfSargableAndRemoveEscapeChars(context, buffer);
assertThat(wildCardPosition).isEqualTo(3);
assertThat(buffer.toString()).isEqualTo("ab__d");
}
@Test
public void testSargableRange() {
String pattern = "abc";
CompiledLiteral literal = new CompiledLiteral(pattern);
CompiledID cid = new CompiledID("val");
CompiledLike cl = new CompiledLike(cid, literal);
CompiledComparison[] cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(1);
ArrayList cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo(pattern);
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_EQ);
pattern = "ab%";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("ab");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
cv = (ArrayList) cc[1].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("ac");
assertThat(cc[1].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_LT);
pattern = "a%c";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(3);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("a");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
cv = (ArrayList) cc[1].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("b");
assertThat(cc[1].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_LT);
assertThat(cc[2]).isEqualTo(cl);
pattern = "%bc";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(cc[1]).isEqualTo(cl);
pattern = "ab_";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(3);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("ab");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
cv = (ArrayList) cc[1].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("ac");
assertThat(cc[1].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_LT);
assertThat(cc[2]).isEqualTo(cl);
pattern = "_bc";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(cc[1]).isEqualTo(cl);
pattern = "a_c";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(3);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("a");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
cv = (ArrayList) cc[1].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("b");
assertThat(cc[1].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_LT);
assertThat(cc[2]).isEqualTo(cl);
pattern = "_b%";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(cc[1]).isEqualTo(cl);
pattern = "a\\%bc";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(1);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("a%bc");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_EQ);
pattern = "ab%";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cl.negate();
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("ab");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
cv = (ArrayList) cc[1].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("ac");
assertThat(cc[1].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_LT);
pattern = "a%c";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cl.negate();
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(cc[1]).isEqualTo(cl);
pattern = "a_";
literal = new CompiledLiteral(pattern);
cl = new CompiledLike(cid, literal);
cl.negate();
cc = cl.getRangeIfSargable(context, cid, pattern);
assertThat(cc.length).isEqualTo(2);
cv = (ArrayList) cc[0].getChildren();
assertThat(cv.get(0)).isInstanceOf(CompiledID.class);
assertThat(((CompiledID) cv.get(0)).getId()).isEqualTo("val");
assertThat(cv.get(1)).isInstanceOf(CompiledLiteral.class);
assertThat(((CompiledLiteral) cv.get(1))._obj).isEqualTo("");
assertThat(cc[0].getOperator()).isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(cc[1]).isEqualTo(cl);
}
/**
* This test is no more valid. From 6.6 Like is enhanced to support special chars (% and _) at any
* place in the string pattern. With this the Like predicate is not transformed to
* compiled-junction with > and < operator.
*/
@Ignore
@Test
public void testStringConditioningForLike_2() {
CompiledValue var = new CompiledPath(new CompiledID("p"), "ID");
String s1 = "abc%";
CompiledLiteral literal = new CompiledLiteral(s1);
QCompiler compiler = new QCompiler();
CompiledValue result = compiler.createCompiledValueForLikePredicate(var, literal);
validationHelperForCompiledJunction((CompiledJunction) result, "abc", "abd");
s1 = "abc\\\\%";
literal = new CompiledLiteral(s1);
compiler = new QCompiler();
result = compiler.createCompiledValueForLikePredicate(var, literal);
validationHelperForCompiledJunction((CompiledJunction) result, "abc\\\\", "abc\\]");
s1 = "abc" + new String(new char[] {(char) 255, '%'});
literal = new CompiledLiteral(s1);
compiler = new QCompiler();
result = compiler.createCompiledValueForLikePredicate(var, literal);
String lowerBoundKey = "abc" + new String(new char[] {(char) 255});
validationHelperForCompiledJunction((CompiledJunction) result, lowerBoundKey, "abd");
s1 = "abc"
+ new String(new char[] {(char) 255, (char) 255, (char) 255, (char) 255, (char) 255, '%'});
literal = new CompiledLiteral(s1);
compiler = new QCompiler();
result = compiler.createCompiledValueForLikePredicate(var, literal);
lowerBoundKey =
"abc" + new String(new char[] {(char) 255, (char) 255, (char) 255, (char) 255, (char) 255});
validationHelperForCompiledJunction((CompiledJunction) result, lowerBoundKey, "abd");
s1 = "%";
literal = new CompiledLiteral(s1);
compiler = new QCompiler();
result = compiler.createCompiledValueForLikePredicate(var, literal);
assertThat(result).isInstanceOf(CompiledComparison.class);
CompiledComparison cc = (CompiledComparison) result;
assertThat(cc.reflectOnOperator((CompiledValue) cc.getChildren().get(1)))
.isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(((CompiledLiteral) cc.getChildren().get(1))._obj).isEqualTo("");
}
private void validationHelperForCompiledJunction(CompiledJunction result, String lowerBoundKey,
String upperBoundKey) {
assertThat(result.getOperator()).isEqualTo(OQLLexerTokenTypes.LITERAL_and);
List list = result.getChildren();
CompiledComparison lowerBound = (CompiledComparison) list.get(0);
CompiledComparison upperBound = (CompiledComparison) list.get(1);
assertThat(lowerBound.reflectOnOperator((CompiledValue) lowerBound.getChildren().get(1)))
.isEqualTo(OQLLexerTokenTypes.TOK_GE);
assertThat(upperBound.reflectOnOperator((CompiledValue) upperBound.getChildren().get(1)))
.isEqualTo(OQLLexerTokenTypes.TOK_LT);
assertThat(((CompiledLiteral) lowerBound.getChildren().get(1))._obj).isEqualTo(lowerBoundKey);
assertThat(((CompiledLiteral) upperBound.getChildren().get(1))._obj).isEqualTo(upperBoundKey);
}
@Test
public void testLowestString() {
SortedMap<String, String> map = new TreeMap<>();
map.put("ab", "value");
map.put("z", "value");
map.put("v", "value");
SortedMap returnMap = map.tailMap(CompiledLike.LOWEST_STRING);
assertThat(returnMap.size()).isEqualTo(3);
}
@Test
public void testBoundaryChar() {
String s1 = "!";
String s2 = "9";
String s3 = "A";
String s4 = "[";
String s5 = "a";
String s6 = "{";
String s7 = new String(new char[] {(char) 255});
assertThat(s2.compareTo(s1) > 0).isTrue();
assertThat(s3.compareTo(s2) > 0).isTrue();
assertThat(s4.compareTo(s3) > 0).isTrue();
assertThat(s5.compareTo(s4) > 0).isTrue();
assertThat(s6.compareTo(s5) > 0).isTrue();
assertThat(s7.compareTo(s6) > 0).isTrue();
}
@Test
@Parameters({"MIN", "MAX", "AVG", "SUM", "COUNT"})
public void parsingShouldSucceedWhenAggregatesAreUsedAsPartOfTheWhereClauseWithinAnInnerSelectQuery(
String function) {
String[] queries = new String[] {
"SELECT * FROM /region WHERE id IN (SELECT " + function + "(id) FROM /region)",
"SELECT COUNT(id), status FROM /region WHERE id IN (SELECT " + function
+ "(id) FROM /region) GROUP BY status",
"SELECT * FROM /region WHERE id = ELEMENT(SELECT " + function + "(id) FROM /region)",
"SELECT * FROM /region WHERE id < ELEMENT(SELECT " + function + "(id) FROM /region)",
"SELECT * FROM /region WHERE id > ELEMENT(SELECT " + function + "(id) FROM /region)",
"SELECT * FROM /region WHERE id <> ELEMENT(SELECT " + function + "(id) FROM /region)",
"SELECT COUNT(id), status FROM /region WHERE id = ELEMENT(SELECT " + function
+ "(id) FROM /region) GROUP BY status",
"SELECT COUNT(id), status FROM /region WHERE id < ELEMENT(SELECT " + function
+ "(id) FROM /region) GROUP BY status",
"SELECT COUNT(id), status FROM /region WHERE id > ELEMENT(SELECT " + function
+ "(id) FROM /region) GROUP BY status",
"SELECT COUNT(id), status FROM /region WHERE id <> ELEMENT(SELECT " + function
+ "(id) FROM /region) GROUP BY status",
};
for (String queryString : queries) {
QCompiler compiler = new QCompiler();
assertThatCode(() -> compiler.compileQuery(queryString))
.as(String.format("Query parsing failed for %s but should have succeeded.", queryString))
.doesNotThrowAnyException();
}
}
@Test
@Parameters({"MIN", "MAX", "AVG", "SUM", "COUNT"})
public void parsingShouldThrowExceptionWhenAggregatesAreUsedAsPartOfTheWhereClauseWithoutAnInnerSelectQuery(
String function) {
String[] queries = new String[] {
"SELECT * FROM /region WHERE " + function + "(id) > 0",
"SELECT COUNT(id), status FROM /region WHERE " + function + "(id) > 0 GROUP BY status",
"SELECT * FROM /region WHERE " + function + "(id) > 0 OR id < 0",
"SELECT COUNT(id), status FROM /region WHERE " + function
+ "(id) > 0 OR id < 0 GROUP BY status",
"SELECT * FROM /region WHERE id > 0 AND " + function + "(id) > 0",
"SELECT COUNT(id), status FROM /region WHERE id > 0 AND " + function
+ "(id) > 0 GROUP BY status",
"SELECT * FROM /region WHERE " + function + "(id) < ELEMENT(SELECT " + function
+ "(id) FROM /region)",
"SELECT COUNT(id), status FROM /region WHERE " + function + "(id) < ELEMENT(SELECT "
+ function + "(id) FROM /region) GROUP BY status",
"SELECT * FROM /region WHERE id > ELEMENT(SELECT id FROM /region WHERE " + function
+ "(id) > 0)",
"SELECT id, status FROM /region WHERE id > ELEMENT(SELECT id FROM /region WHERE " + function
+ "(id) > 0)"
};
for (String queryString : queries) {
QCompiler compiler = new QCompiler();
assertThatThrownBy(() -> compiler.compileQuery(queryString))
.as(String.format("Query parsing succeeded for %s but should have failed.", queryString))
.isInstanceOf(QueryInvalidException.class)
.hasMessageContaining("Aggregate functions can not be used as part of the WHERE clause");
}
}
}