package net.sourceforge.mayfly.evaluation.condition; import junit.framework.TestCase; import net.sourceforge.mayfly.datastore.DateCell; import net.sourceforge.mayfly.datastore.LongCell; import net.sourceforge.mayfly.datastore.NullCell; import net.sourceforge.mayfly.datastore.Row; import net.sourceforge.mayfly.datastore.TupleBuilder; import net.sourceforge.mayfly.evaluation.NoColumn; import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.command.Command; import net.sourceforge.mayfly.evaluation.expression.CountAll; import net.sourceforge.mayfly.evaluation.expression.ScalarSubselect; import net.sourceforge.mayfly.evaluation.expression.SingleColumn; import net.sourceforge.mayfly.evaluation.expression.literal.IntegerLiteral; import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.evaluation.select.Select; import net.sourceforge.mayfly.parser.Parser; import net.sourceforge.mayfly.util.ImmutableList; public class ConditionTest extends TestCase { public void testSelect() throws Exception { Condition where = new Parser("name='steve'").parseWhere(); Row row1 = new TupleBuilder() .append("name", "steve").asRow(); Row row2 = new TupleBuilder() .append("name", "bob").asRow(); assertTrue(where.evaluate(row1, "table1")); assertFalse(where.evaluate(row2, "table1")); } public void testNull() throws Exception { Condition where = new Equal(new SingleColumn("a"), new IntegerLiteral(5)); Row fiveRow = new TupleBuilder().append("a", 5).asRow(); Row nullRow = new TupleBuilder() .append("a", NullCell.INSTANCE).asRow(); assertTrue(where.evaluate(fiveRow, "table1")); assertFalse(where.evaluate(nullRow, "table1")); } public void testFirstAggregate() throws Exception { assertEquals(null, Condition.TRUE.firstAggregate()); assertEquals(null, new Equal(new SingleColumn("x"), new SingleColumn("y")).firstAggregate()); assertEquals("count(*)", new Equal(new CountAll("count"), new SingleColumn("y")).firstAggregate()); assertEquals("count(*)", new IsNull(new CountAll("count")).firstAggregate()); assertEquals(null, new In(new SingleColumn("x"), new ImmutableList()).firstAggregate()); assertEquals("count(*)", new In(new CountAll("count"), new ImmutableList()).firstAggregate()); assertEquals("count(*)", new In( new SingleColumn("x"), ImmutableList.fromElements(new CountAll("count")) ).firstAggregate() ); assertEquals("count(*)", new Not(new IsNull(new CountAll("count"))).firstAggregate()); assertEquals("count(*)", new Or(new IsNull(new CountAll("count")), Condition.TRUE).firstAggregate()); assertEquals("count(*)", new And(Condition.TRUE, new IsNull(new CountAll("count"))).firstAggregate()); } public void testSubselectsAndFirstAggregate() throws Exception { Select select = (Select) Command.fromSql("select max(x) from foo"); assertEquals(null, new Equal(new ScalarSubselect(select), new IntegerLiteral(5)) .firstAggregate()); assertEquals(null, new SubselectedIn(new SingleColumn("x"), select) .firstAggregate()); assertEquals("count(*)", new SubselectedIn(new CountAll("count"), select) .firstAggregate()); } public void testCheck() throws Exception { ResultRow row = new ResultRow() .withColumn("foo", "a", NullCell.INSTANCE) .withColumn("bar", "a", NullCell.INSTANCE); check("foo.a = bar.a", row); check("foo.a = bar.a and (bar.a < 5 or foo.a <> bar.a)", row); assertNoBaz("baz.a = 7", row); assertNoBaz("foo.a = bar.a and (bar.a = 5 or baz.a = 7)", row); assertNoBaz("not baz.a = foo.a", row); assertNoBaz("baz.a in (3, 4)", row); assertNoBaz("bar.a in (3, baz.a)", row); assertNoBaz("baz.a is null", row); Condition.TRUE.check(row); } public void testSubselectAndCheck() throws Exception { ResultRow row = new ResultRow() .withColumn("foo", "a", NullCell.INSTANCE) .withColumn("bar", "a", NullCell.INSTANCE); assertNoBaz("baz.a in (select a from bar)", row); try { check("foo.a in (select a from bar where baz.a = bar.a)", row); fail(); } catch (NoColumn e) { assertEquals("The query optimizer shouldn't try to move subselects", e.getMessage()); // This would also be acceptable: // assertEquals("no column baz.a", e.getMessage()); } try { check("foo.a in (select max(a) from bar)", row); /* I think we might be able to not throw an exception here without damage to the optimizer. */ fail(); } catch (NoColumn e) { assertEquals("The query optimizer shouldn't try to move subselects", e.getMessage()); } } private void assertNoBaz(String sql, ResultRow row) { try { check(sql, row); fail(); } catch (NoColumn e) { assertEquals("no column baz.a", e.getMessage()); } } private void check(String expressionString, ResultRow row) { Condition condition = parse(expressionString); condition.check(row); } private Condition parse(String expressionString) { Parser parser = new Parser(expressionString); Condition condition = parser.parseCondition().asBoolean(); assertEquals("", parser.remainingTokens()); return condition; } public void testResolve() throws Exception { Condition condition = parse("a >= 5"); ResultRow row = new ResultRow().withColumn("foo", "a", new LongCell(8)); Condition resolved = condition.resolve(row, Evaluator.NO_SUBSELECT_NEEDED); assertTrue(resolved.evaluate(row)); /* This is similar to what happens after a GROUP BY (in which the ResultRow just has some aggregates */ try { resolved.evaluate(new ResultRow()); fail(); } catch (NoColumn expected) { assertEquals("no column a", expected.getMessage()); } } public void testCompareDates() throws Exception { ResultRow row = new ResultRow() .withColumn("foo", "a", new DateCell(2001, 9, 11)) .withColumn("foo", "b", new DateCell(2004, 11, 2)); assertTrue(new Greater( new SingleColumn("b"), new SingleColumn("a")).evaluate(row)); assertFalse(new LessEqual( new SingleColumn("b"), new SingleColumn("a")).evaluate(row)); } }