package net.sourceforge.mayfly.acceptance;
import java.sql.ResultSet;
import java.sql.SQLException;
public class AggregateTest extends SqlTestCase {
public void testBasics() throws Exception {
execute("create table foo (x integer)");
execute("insert into foo (x) values (5)");
execute("insert into foo (x) values (null)");
execute("insert into foo (x) values (9)");
assertResultSet(new String[] { " 9 " }, query("select max(x) from foo"));
assertResultSet(new String[] { " 5 " }, query("select min(x) from foo"));
assertResultSet(new String[] { " 2 " }, query("select count(x) from foo"));
assertResultSet(new String[] { " 3 " }, query("select count(*) from foo"));
assertResultSet(new String[] { " 14 " }, query("select sum(x) from foo"));
assertResultSet(new String[] { " 7 " }, query("select avg(x) from foo"));
}
public void testSelectingResults() throws Exception {
execute("create table foo (x integer, y integer)");
execute("create table bar (x integer, z integer)");
execute("insert into foo(x, y) values (5, 10)");
execute("insert into foo(x, y) values (9, 20)");
execute("insert into bar(x, z) values (9, 100)");
execute("insert into bar(x, z) values (9, 200)");
// Just to make it clear what this looks like before aggregation:
assertResultSet(new String[] { "9, 9, 20, 100 ", "9, 9, 20, 200" },
query("select foo.x, bar.x, y, z from foo inner join bar on foo.x = bar.x")
);
// And the real test:
assertResultSet(new String[] { " 200, 2, 40" },
query("select max(z), count(foo.x), sum(y) from foo inner join bar on foo.x = bar.x")
);
}
public void testJoinAndCount() throws Exception {
execute("create table foo(a integer)");
execute("insert into foo(a) values(7)");
execute("insert into foo(a) values(3)");
execute("create table bar(a integer)");
execute("insert into bar(a) values(13)");
execute("insert into bar(a) values(15)");
execute("insert into bar(a) values(16)");
assertResultSet(new String[] { " 6 " },
query("select count(*) from foo inner join bar on 1 = 1")
);
}
public void testColumnAndAggregate() throws Exception {
execute("create table foo (x integer)");
expectQueryFailure("select x, max(x) from foo",
"x is a column but max(x) is an aggregate");
expectQueryFailure("select X + 1, Max ( x ) from foo",
"X is a column but Max(x) is an aggregate");
expectQueryFailure("select 5 + x , MAX(X) from foo",
"x is a column but MAX(X) is an aggregate");
expectQueryFailure("select max(x) + 4, x from foo",
"x is a column but max(x) is an aggregate");
expectQueryFailure("select 3 + max(x) , x from foo",
"x is a column but max(x) is an aggregate");
expectQueryFailure("select foo.*, min(x) from foo",
"foo.x is a column but min(x) is an aggregate");
expectQueryFailure("select x, max(distinct x) from foo",
"x is a column but max(distinct x) is an aggregate");
}
public void testColumnOperatorAggregate() throws Exception {
execute("create table foo (x integer)");
String sql = "select x + min(x) from foo";
if (dialect.disallowColumnAndAggregateInExpression()) {
expectQueryFailure(sql, "x is a column but min(x) is an aggregate");
}
else {
assertResultSet(new String[] { " null " }, query(sql));
}
}
public void testColumnAndCountAll() throws Exception {
execute("create table foo (x integer)");
expectQueryFailure("select x, coUNt ( * ) from foo",
"x is a column but coUNt(*) is an aggregate");
}
public void testLiteralAndAggregate() throws Exception {
execute("create table foo (x integer)");
execute("insert into foo (x) values (5)");
assertResultSet(new String[] { " 3, 5 " },
query("select 3, max(x) from foo"));
}
public void testLiteralAndColumn() throws Exception {
execute("create table foo (x integer)");
execute("insert into foo (x) values (5)");
assertResultSet(new String[] { " 3, 5 " },
query("select 3, x from foo"));
}
public void testBadColumnName() throws Exception {
execute("create table foo (x integer)");
execute("insert into foo (x) values (5)");
execute("insert into foo (x) values (null)");
execute("insert into foo (x) values (9)");
expectQueryFailure("select max(y) from foo", "no column y");
}
public void testWhere() throws Exception {
execute("create table foo (x integer, y integer)");
execute("insert into foo (x, y) values (5, 10)");
execute("insert into foo (x, y) values (null, 10)");
execute("insert into foo (x, y) values (9, 9)");
assertResultSet(new String[] { " 5 " },
query("select max(x) from foo where y = 10"));
}
public void testAggregateInWhere() throws Exception {
execute("create table foo (x integer, y integer, z integer)");
execute("insert into foo (x, y, z) values (5, 10, null)");
execute("insert into foo (x, y, z) values (null, 10, null)");
execute("insert into foo (x, y, z) values (9, 9, null)");
expectQueryFailure("select max(x) from foo where count(y) > 0",
"aggregate count(y) not valid in WHERE");
expectQueryFailure("select max(x) from foo where count(z) > 0",
"aggregate count(z) not valid in WHERE");
expectQueryFailure("select x from foo where count(y) > 0",
"aggregate count(y) not valid in WHERE");
}
public void testNoRows() throws Exception {
execute("create table foo (x integer)");
assertResultSet(new String[] { " null " },
query("select max(x) from foo"));
assertResultSet(new String[] { " null " },
query("select min(x) from foo"));
assertResultSet(new String[] { " 0 " },
query("select count(x) from foo"));
assertResultSet(new String[] { " 0 " },
query("select count(*) from foo"));
assertResultSet(new String[] { " null " },
query("select sum(x) from foo"));
assertResultSet(new String[] { " null " },
query("select avg(x) from foo"));
expectQueryFailure("select max(y) from foo", "no column y");
}
public void testNullRowsOnly() throws Exception {
execute("create table foo (x integer)");
execute("insert into foo (x) values (null)");
assertResultSet(new String[] { " null " }, query("select max(x) from foo"));
assertResultSet(new String[] { " null " }, query("select min(x) from foo"));
assertResultSet(new String[] { " 0 " }, query("select count(x) from foo"));
assertResultSet(new String[] { " 1 " }, query("select count(*) from foo"));
assertResultSet(new String[] { " null " }, query("select sum(x) from foo"));
assertResultSet(new String[] { " null " }, query("select avg(x) from foo"));
expectQueryFailure("select max(y) from foo", "no column y");
}
public void testNullRowsOnlyWithStrings() throws Exception {
execute("create table foo (x varchar(255))");
execute("insert into foo (x) values (null)");
assertResultSet(new String[] { " null " }, query("select max(x) from foo"));
assertResultSet(new String[] { " null " }, query("select min(x) from foo"));
assertResultSet(new String[] { " 0 " }, query("select count(x) from foo"));
assertResultSet(new String[] { " 1 " }, query("select count(*) from foo"));
String sum = "select sum(x) from foo";
String average = "select avg(x) from foo";
if (dialect.canSumStrings(false)) {
assertResultSet(new String[] { " null " }, query(sum));
assertResultSet(new String[] { " null " }, query(average));
}
else {
expectQueryFailure(sum, "attempt to sum string column x");
expectQueryFailure(average, "attempt to average string column x");
}
}
public void testAggregateExpression() throws Exception {
execute("create table foo (x integer)");
execute("insert into foo (x) values (5)");
assertResultSet(new String[] { " 6 " }, query("select 1 + max(x) from foo"));
expectQueryFailure("select 'L' || max(y) from foo", "no column y");
}
public void testCountDistinctAndAll() throws Exception {
execute("create table foo (x integer, y integer)");
execute("insert into foo (x, y) values (5, 60)");
execute("insert into foo (x, y) values (5, 90)");
execute("insert into foo (x, y) values (7, 90)");
assertResultSet(new String[] { " 3 " },
query("select count(x) from foo"));
assertResultSet(new String[] { " 2 " },
query("select count(distinct x) from foo"));
String distinctStar = "select count(distinct *) from foo";
if (dialect.allowCountDistinctStar()) {
assertResultSet(new String[] { " 3 " }, query(distinctStar));
}
else {
expectQueryFailure(distinctStar, "expected expression but got '*'");
}
}
public void testAll() throws Exception {
execute("create table foo (x integer, y integer)");
execute("insert into foo (x, y) values (5, 60)");
execute("insert into foo (x, y) values (5, 90)");
execute("insert into foo (x, y) values (7, 90)");
if (dialect.allowExplicitAllInAggregate()) {
assertResultSet(new String[] { " 3 " },
query("select count(all x) from foo"));
assertResultSet(new String[] { " 80 " },
query("select avg(all y) from foo"));
assertResultSet(new String[] { " 17 " },
query("select sum(all x) from foo"));
assertResultSet(new String[] { " 5 " },
query("select min(all x) from foo"));
assertResultSet(new String[] { " 7 " },
query("select max(all x) from foo"));
}
else {
expectExecuteFailure("select count(all x) from foo", "bad token all");
expectExecuteFailure("select avg(all y) from foo", "bad token all");
expectExecuteFailure("select sum(all x) from foo", "bad token all");
expectExecuteFailure("select min(all x) from foo", "bad token all");
expectExecuteFailure("select max(all x) from foo", "bad token all");
}
}
public void testDistinct() throws Exception {
execute("create table foo (x integer, y integer)");
execute("insert into foo (x, y) values (5, 60)");
execute("insert into foo (x, y) values (5, 90)");
execute("insert into foo (x, y) values (7, 90)");
checkDistinct(75, "select avg(distinct y) from foo");
checkDistinct(12, "select sum(distinct x) from foo");
// Specifying distinct for Minimum/maximum is kind of pointless,
// but legal it would seem
checkDistinct(5, "select min(distinct x) from foo");
checkDistinct(7, "select max(distinct x) from foo");
}
private void checkDistinct(int expected, String sql) throws SQLException {
if (dialect.aggregateDistinctIsForCountOnly()) {
expectQueryFailure(sql, null);
} else {
assertResultSet(new String[] { "" + expected }, query(sql));
}
}
public void testExpression() throws Exception {
execute("create table foo (x integer, y integer)");
execute("insert into foo (x, y) values (10, 20)");
execute("insert into foo (x, y) values (30, 40)");
execute("insert into foo (x, y) values (15, 16)");
assertResultSet(new String[] { " 70 " },
query("select max(x + y) from foo"));
}
public void testAsteriskOnlyForCount() throws Exception {
execute("create table foo (x integer, y integer)");
String averageOfStar = "select avg(*) from foo";
if (dialect.aggregateAsteriskIsForCountOnly()) {
expectQueryFailure(averageOfStar, "expected expression but got '*'");
expectQueryFailure("select sum(*) from foo",
"expected expression but got '*'");
expectQueryFailure("select min(*) from foo",
"expected expression but got '*'");
expectQueryFailure("select max(*) from foo",
"expected expression but got '*'");
}
else {
ResultSet results = query(averageOfStar);
results.close();
}
}
public void testStrings() throws Exception {
execute("create table foo (x varchar(255), y varchar(255))");
execute("insert into foo (x, y) values ('one', 'a')");
execute("insert into foo (x, y) values ('one', 'b')");
execute("insert into foo (x, y) values ('two', 'a')");
assertResultSet(new String[] { " 3 " },
query("select count(*) from foo"));
assertResultSet(new String[] { " 3 " },
query("select count(x) from foo"));
assertResultSet(new String[] { " 2 " },
query("select count(distinct x) from foo"));
// string sort (just like ORDER BY)
assertResultSet(new String[] { " 'one' " },
query("select min(x) from foo"));
assertResultSet(new String[] { " 'two' " },
query("select max(x) from foo"));
String sum = "select sum(x) from foo";
String average = "select avg(x) from foo";
if (dialect.canSumStrings(true)) {
/* Is this parsing the string for a number, or just using zero?
Do we care? */
assertResultSet(new String[] { " 0 " }, query(sum));
assertResultSet(new String[] { " 0 " }, query(average));
}
else {
expectQueryFailure(sum,
"attempt to apply sum(x) to string 'one'");
expectQueryFailure(average,
"attempt to apply avg(x) to string 'one'");
}
}
public void testColumnAlias() throws Exception {
execute("create table foo(displayName varchar(255))");
execute("insert into foo values('center1')");
execute("insert into foo values('another center')");
/* First without the column alias, just to show it
shouldn't matter */
assertResultSet(new String[] { " 0 " },
query(
"select count(*) from foo center " +
"where center.displayName='no such center'"
)
);
assertResultSet(new String[] { " 1 " },
query(
"select count(*) from foo center " +
"where center.displayName='center1'"
)
);
/* Now with the column alias */
assertResultSet(new String[] { " 0 " },
query(
"select count(*) as col_0_0_ from foo center " +
"where center.displayName='no such center'"
)
);
assertResultSet(new String[] { " 1 " },
query(
"select count(*) as col_0_0_ from foo center " +
"where center.displayName='center1'"
)
);
}
}