mayfly-commits Mailing List for Mayfly
Status: Alpha
Brought to you by:
kingdon
You can subscribe to this list here.
2005 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(310) |
Nov
(192) |
Dec
(117) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2006 |
Jan
(217) |
Feb
(18) |
Mar
(109) |
Apr
(94) |
May
(6) |
Jun
(4) |
Jul
(6) |
Aug
(71) |
Sep
(181) |
Oct
(314) |
Nov
(229) |
Dec
(130) |
2007 |
Jan
(10) |
Feb
(48) |
Mar
(47) |
Apr
(4) |
May
(21) |
Jun
(27) |
Jul
(19) |
Aug
|
Sep
(7) |
Oct
(17) |
Nov
(60) |
Dec
(25) |
2008 |
Jan
(7) |
Feb
(64) |
Mar
(30) |
Apr
(4) |
May
(6) |
Jun
(2) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <ki...@us...> - 2008-08-09 16:51:38
|
Revision: 565 http://mayfly.svn.sourceforge.net/mayfly/?rev=565&view=rev Author: kingdon Date: 2008-08-09 16:51:34 +0000 (Sat, 09 Aug 2008) Log Message: ----------- More tests of LIKE, and a bit of immutable object work. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OrderItem.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AllColumnsFromTable.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/WhereTest.java Added Paths: ----------- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/LikeTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java 2008-08-09 16:51:34 UTC (rev 565) @@ -9,6 +9,11 @@ import net.sourceforge.mayfly.evaluation.what.WhatElement; import net.sourceforge.mayfly.parser.Location; +/** + * @internal + * Expressions should be immutable. I think that is probably true now + * (certainly it is the intention, as they go in the store). + */ abstract public class Expression extends WhatElement { /* Storing a location here is dubious because an expression can Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java 2008-08-09 16:51:34 UTC (rev 565) @@ -3,6 +3,11 @@ import net.sourceforge.mayfly.evaluation.ResultRows; import net.sourceforge.mayfly.evaluation.what.Selected; +/** + * @internal + * Implementations of this class should be immutable (or have no state at + * all). + */ public abstract class Distinct { abstract public ResultRows distinct(Selected selected, ResultRows rows); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OrderItem.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OrderItem.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OrderItem.java 2008-08-09 16:51:34 UTC (rev 565) @@ -3,6 +3,10 @@ import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.what.What; +/** + * @internal + * Implementations of this class should be immutable. + */ abstract public class OrderItem { private final boolean ascending; Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java 2008-08-09 16:51:34 UTC (rev 565) @@ -85,6 +85,7 @@ } /** + * @internal * Currently this method makes joins explicit and also moves * conditions from WHERE to ON. The whole thing would probably * be cleaner if those were separated. The Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AllColumnsFromTable.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AllColumnsFromTable.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AllColumnsFromTable.java 2008-08-09 16:51:34 UTC (rev 565) @@ -4,7 +4,7 @@ public class AllColumnsFromTable extends WhatElement { - private String aliasOrTable; + private final String aliasOrTable; public AllColumnsFromTable(String aliasOrTable) { this.aliasOrTable = aliasOrTable; Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java 2008-08-09 16:51:34 UTC (rev 565) @@ -486,6 +486,10 @@ // messages case-preserving in general. return false; } + + public boolean likeIsCaseSensitive() { + return true; + } public boolean haveSlashStarComments() { return true; Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java 2008-08-09 16:51:34 UTC (rev 565) @@ -436,5 +436,10 @@ public boolean callJavaMethodAsStoredProcedure() { return false; } + + @Override + public boolean likeIsCaseSensitive() { + return false; + } } Added: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/LikeTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/LikeTest.java (rev 0) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/LikeTest.java 2008-08-09 16:51:34 UTC (rev 565) @@ -0,0 +1,60 @@ +package net.sourceforge.mayfly.acceptance.expression; + +import net.sourceforge.mayfly.acceptance.SqlTestCase; + +/** + * @internal + * See also {@link WhereTest#testLikePrecedence()} although that is about + * parsing/precedence as much as LIKE. + */ +public class LikeTest extends SqlTestCase { + + public void testBasics() throws Exception { + execute("create table foo(a varchar(255))"); + execute("insert into foo(a) values('cat')"); + execute("insert into foo(a) values('cut')"); + execute("insert into foo(a) values('category')"); + execute("insert into foo(a) values('tomcat')"); + execute("insert into foo(a) values('dog')"); + execute("insert into foo(a) values(null)"); + + assertResultSet(new String[] { " 'cat' " }, + query("select a from foo where a like 'cat'")); + assertResultSet(new String[] { " 'cat' ", " 'category' " }, + query("select a from foo where a like 'cat%'")); + assertResultSet(new String[] { + " 'cat' ", " 'category' ", " 'tomcat' " }, + query("select a from foo where a like '%cat%'")); + assertResultSet(new String[] { + " 'cat' ", " 'tomcat' " }, + query("select a from foo where a like '%cat'")); + + assertResultSet(new String[] { " 'cat' " , " 'cut' " }, + query("select a from foo where a like 'c_t'")); + } + + public void testCaseInsensitive() throws Exception { + execute("create table foo(a varchar(255))"); + execute("insert into foo(a) values('CAP')"); + execute("insert into foo(a) values('cap')"); + execute("insert into foo(a) values('Cap')"); + + if (dialect.likeIsCaseSensitive()) { + assertResultSet(new String[] { " 'cap' " }, + query("select a from foo where a like 'cap'")); + assertResultSet(new String[] { " 'CAP' "}, + query("select a from foo where a like 'CAP'")); + assertResultSet(new String[] { }, + query("select a from foo where a like 'caP'")); + } + else { + assertResultSet(new String[] { " 'cap' ", " 'Cap' ", " 'CAP' " }, + query("select a from foo where a like 'cap'")); + assertResultSet(new String[] { " 'cap' ", " 'Cap' ", " 'CAP' " }, + query("select a from foo where a like 'CAP'")); + assertResultSet(new String[] { " 'cap' ", " 'Cap' ", " 'CAP' " }, + query("select a from foo where a like 'caP'")); + } + } + +} Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/WhereTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/WhereTest.java 2008-06-16 04:49:40 UTC (rev 564) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/WhereTest.java 2008-08-09 16:51:34 UTC (rev 565) @@ -344,28 +344,4 @@ } } - public void testLike() throws Exception { - execute("create table foo(a varchar(255))"); - execute("insert into foo(a) values('cat')"); - execute("insert into foo(a) values('cut')"); - execute("insert into foo(a) values('category')"); - execute("insert into foo(a) values('tomcat')"); - execute("insert into foo(a) values('dog')"); - execute("insert into foo(a) values(null)"); - - assertResultSet(new String[] { " 'cat' " }, - query("select a from foo where a like 'cat'")); - assertResultSet(new String[] { " 'cat' ", " 'category' " }, - query("select a from foo where a like 'cat%'")); - assertResultSet(new String[] { - " 'cat' ", " 'category' ", " 'tomcat' " }, - query("select a from foo where a like '%cat%'")); - assertResultSet(new String[] { - " 'cat' ", " 'tomcat' " }, - query("select a from foo where a like '%cat'")); - - assertResultSet(new String[] { " 'cat' " , " 'cut' " }, - query("select a from foo where a like 'c_t'")); - } - } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-06-16 04:49:42
|
Revision: 564 http://mayfly.svn.sourceforge.net/mayfly/?rev=564&view=rev Author: kingdon Date: 2008-06-15 21:49:40 -0700 (Sun, 15 Jun 2008) Log Message: ----------- Another test for the last checkin. Added Paths: ----------- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromElementTest.java Added: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromElementTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromElementTest.java (rev 0) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromElementTest.java 2008-06-16 04:49:40 UTC (rev 564) @@ -0,0 +1,45 @@ +package net.sourceforge.mayfly.evaluation.from; + +import junitx.framework.ObjectAssert; + +import net.sourceforge.mayfly.evaluation.condition.And; +import net.sourceforge.mayfly.evaluation.condition.Condition; +import net.sourceforge.mayfly.evaluation.condition.Equal; +import net.sourceforge.mayfly.evaluation.condition.Greater; + +import org.junit.Test; + + +public class FromElementTest { + + @Test + public void addToCondition() { + FromElement start = + new InnerJoin(new FromTable("foo"), new FromTable("bar"), Condition.TRUE); + InnerJoin result = (InnerJoin) start.addToCondition(new Equal(null, null)); + ObjectAssert.assertInstanceOf(Equal.class, result.condition); + } + + @Test + public void addToConditionCreatesAnd() { + FromElement start = + new InnerJoin(new FromTable("foo"), new FromTable("bar"), + new Greater(null, null)); + InnerJoin result = (InnerJoin) start.addToCondition(new Equal(null, null)); + And and = (And) result.condition; + ObjectAssert.assertInstanceOf(Greater.class, and.leftSide); + ObjectAssert.assertInstanceOf(Equal.class, and.rightSide); + } + + @Test + public void addToConditionWorksForLeftJoin() { + FromElement start = + new LeftJoin(new FromTable("foo"), new FromTable("bar"), + new Greater(null, null)); + LeftJoin result = (LeftJoin) start.addToCondition(new Equal(null, null)); + And and = (And) result.condition; + ObjectAssert.assertInstanceOf(Greater.class, and.leftSide); + ObjectAssert.assertInstanceOf(Equal.class, and.rightSide); + } + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-06-16 04:47:15
|
Revision: 563 http://mayfly.svn.sourceforge.net/mayfly/?rev=563&view=rev Author: kingdon Date: 2008-06-15 21:47:12 -0700 (Sun, 15 Jun 2008) Log Message: ----------- Various cleanups to planner. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/datastore/Columns.java trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Aggregator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupItem.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromElement.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromTable.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/InnerJoin.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/LeftJoin.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java trunk/mayfly/test/net/sourceforge/mayfly/datastore/TableReferenceTest.java trunk/mayfly/test/net/sourceforge/mayfly/datastore/constraint/ForeignKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromTableTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/Columns.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/Columns.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/Columns.java 2008-06-16 04:47:12 UTC (rev 563) @@ -6,7 +6,6 @@ import net.sourceforge.mayfly.util.CaseInsensitiveString; import net.sourceforge.mayfly.util.ImmutableList; import net.sourceforge.mayfly.util.ImmutableMap; -import net.sourceforge.mayfly.util.L; import java.util.ArrayList; import java.util.HashMap; @@ -15,30 +14,37 @@ import java.util.Map; public class Columns implements Iterable<Column> { - public static Columns fromColumnNames(List columnNameStrings) { - L columnList = new L(); - for (Iterator iter = columnNameStrings.iterator(); iter.hasNext();) { - String name = (String) iter.next(); + public static Columns fromColumnNames(Iterable<String> names) { + List<Column> columnList = new ArrayList<Column>(); + for (String name : names) { columnList.add(new Column(name)); } - return new Columns(columnList.asImmutable()); + return new Columns(new ImmutableList(columnList)); } + + public static Columns fromColumnNames(String... names) { + List<Column> columnList = new ArrayList<Column>(); + for (String name : names) { + columnList.add(new Column(name)); + } + return new Columns(new ImmutableList(columnList)); + } + public static Columns singleton(Column column) { return new Columns( ImmutableList.fromArray(new Column[] { column })); } - final ImmutableList columnNames; + final ImmutableList<CaseInsensitiveString> columnNames; final ImmutableMap nameToColumn; - public Columns(ImmutableList columns) { + public Columns(ImmutableList<Column> columns) { List names = new ArrayList(); Map map = new HashMap(); - for (Iterator iter = columns.iterator(); iter.hasNext();) { - Column column = (Column) iter.next(); + for (Column column : columns) { CaseInsensitiveString name = column.columnName; names.add(name); Object oldColumn = map.put(name, column); @@ -46,11 +52,11 @@ throw new MayflyException("duplicate column " + name); } } - this.columnNames = new ImmutableList(names); + this.columnNames = new ImmutableList<CaseInsensitiveString>(names); this.nameToColumn = new ImmutableMap(map); } - private Columns(ImmutableList names, ImmutableMap map) { + private Columns(ImmutableList<CaseInsensitiveString> names, ImmutableMap map) { this.columnNames = names; this.nameToColumn = map; } @@ -78,17 +84,15 @@ }; } - public ImmutableList asNames() { - List names = new ArrayList(); - for (int i = 0; i < columnNames.size(); ++i) { - CaseInsensitiveString column = (CaseInsensitiveString) - columnNames.get(i); + public ImmutableList<String> asNames() { + List<String> names = new ArrayList<String>(); + for (CaseInsensitiveString column : columnNames) { names.add(column.getString()); } - return new ImmutableList(names); + return new ImmutableList<String>(names); } - public ImmutableList asCaseNames() { + public ImmutableList<CaseInsensitiveString> asCaseNames() { return columnNames; } Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java 2008-06-16 04:47:12 UTC (rev 563) @@ -30,13 +30,21 @@ this.tables = tables; } - public Schema createTable(String table, List columnNames) { + public Schema createTable(String table, Iterable<String> columnNames) { return createTable( table, Columns.fromColumnNames(columnNames), new Constraints(), new ImmutableList()); } + + public Schema createTable(String table, String... columnNames) { + return createTable( + table, + Columns.fromColumnNames(columnNames), + new Constraints(), + new ImmutableList()); + } public Schema createTable( String table, Columns columns, Constraints constraints, Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Aggregator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Aggregator.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Aggregator.java 2008-06-16 04:47:12 UTC (rev 563) @@ -5,7 +5,7 @@ /** * @internal - * Not yet immutable, because of {@link GroupByKeys} + * Implementations of this interface should be immutable. */ public interface Aggregator { @@ -14,5 +14,7 @@ public abstract ResultRow check( ResultRow dummyRow, Evaluator evaluator, Selected selected); + + public abstract Aggregator resolve(ResultRow dummyRow, Evaluator evaluator); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java 2008-06-16 04:47:12 UTC (rev 563) @@ -9,16 +9,20 @@ public class GroupBy implements Aggregator { private final GroupByKeys keys; - private Condition having; + private final Condition having; public GroupBy(ImmutableList<GroupItem> items, Condition having) { - keys = new GroupByKeys(items); - this.having = having; + this(new GroupByKeys(items), having); } public GroupBy(GroupItem... item) { this(ImmutableList.fromArray(item), Condition.TRUE); } + + public GroupBy(GroupByKeys keys, Condition having) { + this.keys = keys; + this.having = having; + } public GroupedRows makeGroupedRows(ResultRows resultRows, Evaluator evaluator) { GroupedRows grouped = new GroupedRows(); @@ -33,10 +37,18 @@ return resultOfGrouping.select(having, evaluator); } + public Aggregator resolve(ResultRow afterJoins, Evaluator evaluator) { + Condition newHaving = having.resolve(afterJoins, evaluator); + GroupByKeys newKeys = keys.resolve(afterJoins, evaluator); + if (newHaving != having || newKeys != keys) { + return new GroupBy(newKeys, newHaving); + } + else { + return this; + } + } + public ResultRow check(ResultRow afterJoins, Evaluator evaluator, Selected selected) { - having = having.resolve(afterJoins, evaluator); - keys.resolve(afterJoins, evaluator); - GroupedRows grouped = makeGroupedRows(new ResultRows(afterJoins), evaluator); ResultRows resultOfGrouping = grouped.ungroup(selected); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java 2008-06-16 04:47:12 UTC (rev 563) @@ -8,10 +8,6 @@ import java.util.Collections; import java.util.List; -/** - * @internal - * Not yet immutable, because of {@link GroupItem} - */ public class GroupByKeys { private final ImmutableList<GroupItem> items; @@ -53,10 +49,22 @@ return false; } - public void resolve(ResultRow row, Evaluator evaluator) { + public GroupByKeys resolve(ResultRow row, Evaluator evaluator) { + List<GroupItem> resolvedItems = new ArrayList<GroupItem>(); + boolean changed = false; for (GroupItem item : items) { - item.resolve(row, evaluator); + GroupItem resolved = item.resolve(row, evaluator); + if (resolved != item) { + changed = true; + } + resolvedItems.add(resolved); } + if (changed) { + return new GroupByKeys(new ImmutableList(resolvedItems)); + } + else { + return this; + } } public int size() { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupItem.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupItem.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupItem.java 2008-06-16 04:47:12 UTC (rev 563) @@ -6,10 +6,7 @@ public class GroupItem { - /** - * Not yet immutable, because of {@link #resolve(ResultRow, Evaluator)}. - */ - private Expression expression; + private final Expression expression; public GroupItem(Expression expression) { this.expression = expression; @@ -29,8 +26,14 @@ return expression; } - public void resolve(ResultRow row, Evaluator evaluator) { - expression = expression.resolve(row, evaluator); + public GroupItem resolve(ResultRow row, Evaluator evaluator) { + Expression resolved = expression.resolve(row, evaluator); + if (resolved == expression) { + return this; + } + else { + return new GroupItem(resolved); + } } } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java 2008-06-16 04:47:12 UTC (rev 563) @@ -42,4 +42,8 @@ } } + public Aggregator resolve(ResultRow dummyRow, Evaluator evaluator) { + return this; + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java 2008-06-16 04:47:12 UTC (rev 563) @@ -8,11 +8,8 @@ /** * @internal - * The intention is that a condition should be immutable. Right now - * the condition subclasses themselves don't always enforce this but - * mutating the condition, after its initial construction, is not - * allowed as it is in the data store. (The subclass in question is - * {@link SubselectedIn}). + * I believe that conditions are now immutable. Certainly that + * is the intention (since they can be kept in the data store). */ public abstract class Condition { @@ -61,4 +58,21 @@ return Location.UNKNOWN; } + /** + * @internal + * Construct a condition which behaves like this AND right + */ + public Condition makeAnd(Condition right) { + // Turn "foo and true" into "foo" (mainly to make unit tests easier). + if (this instanceof True) { + return right; + } + else if (right instanceof True) { + return this; + } + else { + return new And(this, right); + } + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromElement.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromElement.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromElement.java 2008-06-16 04:47:12 UTC (rev 563) @@ -2,6 +2,7 @@ import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.ResultRows; +import net.sourceforge.mayfly.evaluation.condition.Condition; import net.sourceforge.mayfly.evaluation.select.Evaluator; /** @@ -14,4 +15,8 @@ public abstract ResultRow dummyRow(Evaluator evaluator); + public FromElement addToCondition(Condition conditionToAndIn) { + return this; + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromTable.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromTable.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/FromTable.java 2008-06-16 04:47:12 UTC (rev 563) @@ -62,9 +62,7 @@ private ResultRow applyAlias(Row row, Columns tableColumns, Options options) { ResultRow result = new ResultRow(); - for (Iterator iter = tableColumns.asCaseNames().iterator(); - iter.hasNext(); ) { - CaseInsensitiveString column = (CaseInsensitiveString) iter.next(); + for (CaseInsensitiveString column : tableColumns.asCaseNames()) { result = result.with( new SingleColumn(alias, column.getString(), options), row.cell(column)); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/InnerJoin.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/InnerJoin.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/InnerJoin.java 2008-06-16 04:47:12 UTC (rev 563) @@ -17,5 +17,10 @@ .join(right.tableContents(evaluator)); return unfiltered.select(condition, evaluator); } + + @Override + public FromElement addToCondition(Condition conditionToAndIn) { + return new InnerJoin(left, right, condition.makeAnd(conditionToAndIn)); + } } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/LeftJoin.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/LeftJoin.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/LeftJoin.java 2008-06-16 04:47:12 UTC (rev 563) @@ -47,4 +47,9 @@ return new ResultRows(joinResult.asImmutable()); } + @Override + public FromElement addToCondition(Condition conditionToAndIn) { + return new LeftJoin(left, right, condition.makeAnd(conditionToAndIn)); + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java 2008-06-16 04:47:12 UTC (rev 563) @@ -1,7 +1,5 @@ package net.sourceforge.mayfly.evaluation.select; -import java.util.Iterator; - import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.evaluation.Aggregator; @@ -11,7 +9,6 @@ import net.sourceforge.mayfly.evaluation.ResultRows; import net.sourceforge.mayfly.evaluation.condition.And; import net.sourceforge.mayfly.evaluation.condition.Condition; -import net.sourceforge.mayfly.evaluation.condition.True; import net.sourceforge.mayfly.evaluation.from.From; import net.sourceforge.mayfly.evaluation.from.FromElement; import net.sourceforge.mayfly.evaluation.from.InnerJoin; @@ -30,7 +27,9 @@ // mutated as we move conditions from WHERE to ON private Condition where; - private final Aggregator groupBy; + // mutated when we resolve + private Aggregator groupBy; + private final Distinct distinct; private final OrderBy orderBy; private final Limit limit; @@ -46,13 +45,6 @@ this.limit = limit; } - public OptimizedSelect planForTests() { - optimize(); - return new OptimizedSelect( - null, null, null, - from.soleElement(), where, groupBy, distinct, orderBy, what, limit); - } - public OptimizedSelect plan(Evaluator evaluator) { Evaluator aliasEvaluator = new AliasEvaluator(what, evaluator); @@ -67,13 +59,13 @@ } private void check(Evaluator evaluator, Selected selected, ResultRow dummyRow) { - for (Iterator iter = selected.iterator(); iter.hasNext();) { - Expression element = (Expression) iter.next(); + for (Expression element : selected) { element.evaluate(dummyRow, evaluator); } where.evaluate(dummyRow, evaluator); where.rejectAggregates("WHERE"); + groupBy = groupBy.resolve(dummyRow, evaluator); ResultRow groupedDummyRow = groupBy.check(dummyRow, evaluator, selected); ResultRows afterDistinct = @@ -92,24 +84,20 @@ return element.dummyRow(evaluator); } - public void optimize() { - optimize(null); - } - /** * Currently this method makes joins explicit and also moves * conditions from WHERE to ON. The whole thing would probably - * be cleaner if those were separated. The second step - * would be optional (for those tests currently passing in - * null for store) and the {@link #dummyRow(int, DataStore, String)} + * be cleaner if those were separated. The + * {@link #dummyRow(int, DataStore, String)} * method could make use of the joins which were built up * in the first step. */ - public void optimize(Evaluator evaluator) { - if (evaluator != null) { - ResultRow fullDummyRow = dummyRow(0, evaluator); - where.evaluate(fullDummyRow, evaluator); + private void optimize(Evaluator evaluator) { + if (evaluator == null) { + throw new NullPointerException("evaluator is required"); } + ResultRow fullDummyRow = dummyRow(0, evaluator); + where.evaluate(fullDummyRow, evaluator); while (from.size() > 1) { // x y z -> join(x, y) z @@ -122,8 +110,14 @@ from = from.without(0).without(0).with(0, explicitJoin); } + + moveAllWhereToOn(evaluator); } + private void moveAllWhereToOn(Evaluator evaluator) { + // Currently handled in optimize method + } + ResultRow dummyRow(int index, Evaluator evaluator) { ResultRow dummyRow = from.element(index).dummyRow(evaluator); if (index >= from.size() - 1) { @@ -138,11 +132,6 @@ private Condition moveWhereToOn( FromElement first, FromElement second, Evaluator evaluator) { - if (evaluator == null) { - // For convenience in tests. - return Condition.TRUE; - } - MoveResult result = new MoveResult(); moveToResult(first, second, evaluator, result, where); where = result.nonMovable; @@ -153,7 +142,7 @@ Evaluator evaluator, final MoveResult moveResult, Condition toAnalyze) { if (canMove(toAnalyze, first, second, evaluator)) { - moveResult.toBeMoved = makeAnd(toAnalyze, moveResult.toBeMoved); + moveResult.toBeMoved = toAnalyze.makeAnd(moveResult.toBeMoved); } else if (toAnalyze instanceof And) { And and = (And) toAnalyze; @@ -165,19 +154,6 @@ } } - private Condition makeAnd(Condition left, Condition right) { - // Turn "foo and true" into "foo" (mainly to make unit tests easier). - if (left instanceof True) { - return right; - } - else if (right instanceof True) { - return left; - } - else { - return new And(left, right); - } - } - static class MoveResult { Condition toBeMoved = Condition.TRUE; Condition nonMovable = Condition.TRUE; Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java 2008-06-16 04:47:12 UTC (rev 563) @@ -5,7 +5,6 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.evaluation.Aggregator; -import net.sourceforge.mayfly.evaluation.GroupByKeys; import net.sourceforge.mayfly.evaluation.command.Command; import net.sourceforge.mayfly.evaluation.command.UpdateStore; import net.sourceforge.mayfly.evaluation.condition.Condition; @@ -21,9 +20,6 @@ private final Condition where; - /** - * Not immutable, because of {@link GroupByKeys} - */ private final Aggregator groupBy; private final Distinct distinct; Modified: trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-06-16 04:47:12 UTC (rev 563) @@ -1627,30 +1627,29 @@ } private FromElement parseFromItem() { + FromElement left; if (consumeIfMatches(TokenType.OPEN_PAREN)) { - FromElement fromElement = parseFromItem(); + left = parseFromItem(); expectAndConsume(CLOSE_PAREN); - return fromElement; } + else { + left = parseFromTable(); + } - FromElement left = parseFromTable(); while (true) { - if (currentToken.type == TokenType.KEYWORD_cross) { - expectAndConsume(TokenType.KEYWORD_cross); + if (consumeIfMatches(TokenType.KEYWORD_cross)) { expectAndConsume(TokenType.KEYWORD_join); FromElement right = parseFromItem(); left = new InnerJoin(left, right, Condition.TRUE); } - else if (currentToken.type == TokenType.KEYWORD_inner) { - expectAndConsume(TokenType.KEYWORD_inner); + else if (consumeIfMatches(TokenType.KEYWORD_inner)) { expectAndConsume(TokenType.KEYWORD_join); FromElement right = parseFromItem(); expectAndConsume(TokenType.KEYWORD_on); Condition condition = parseWhere(); left = new InnerJoin(left, right, condition); } - else if (currentToken.type == TokenType.KEYWORD_left) { - expectAndConsume(TokenType.KEYWORD_left); + else if (consumeIfMatches(TokenType.KEYWORD_left)) { if (currentToken.type == TokenType.KEYWORD_outer) { expectAndConsume(TokenType.KEYWORD_outer); } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -424,6 +424,38 @@ ); } + public void testParenthesesAndJoins() throws Exception { + execute("create table apple(a varchar(255))"); + execute("create table banana(b varchar(255))"); + execute("create table carrot(c varchar(255))"); + execute("insert into apple(a) values('aa')"); + execute("insert into banana(b) values('bb')"); + execute("insert into carrot(c) values('cc')"); + + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query("select a, b, c from apple, banana, carrot")); + + String simpleCrossJoin = "select a, b, c from apple cross join banana cross join carrot"; + if (dialect.crossJoinRequiresOn()) { + expectExecuteFailure(simpleCrossJoin, "expected ON but got CROSS"); + return; + } + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query(simpleCrossJoin)); + + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query("select a, b, c from apple cross join banana, carrot")); + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query("select a, b, c from apple, banana cross join carrot")); + // Those were warmups. Here we start in on parens + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query("select a, b, c from (apple cross join banana) cross join carrot")); + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query("select a, b, c from apple cross join (banana cross join carrot)")); + assertResultSet(new String[] { " 'aa', 'bb', 'cc' " }, + query("select a, b, c from apple inner join (banana cross join carrot) on a = 'aa' ")); + } + public void testJoinOnNull() throws Exception { // This case is mentioned in the documentation for // hypersonic 1.8.x. Modified: trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -5,13 +5,11 @@ import net.sourceforge.mayfly.evaluation.ValueList; import net.sourceforge.mayfly.util.ImmutableList; -import java.util.Collections; - public class DataStoreTest extends TestCase { public void testAddRowWithSchemaAndColumnNames() throws Exception { DataStore store = new DataStore() - .addSchema("mars", new Schema().createTable("foo", Collections.singletonList("x"))); + .addSchema("mars", new Schema().createTable("foo", "x")); DataStore newStore = store.addRow( new TableReference("mars", "foo"), ImmutableList.singleton("x"), ValueList.singleton(new LongCell(5)), Modified: trunk/mayfly/test/net/sourceforge/mayfly/datastore/TableReferenceTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/datastore/TableReferenceTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/datastore/TableReferenceTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -3,14 +3,13 @@ import junit.framework.TestCase; import net.sourceforge.mayfly.evaluation.command.UnresolvedTableReference; -import net.sourceforge.mayfly.util.ImmutableList; public class TableReferenceTest extends TestCase { public void testCanonicalizeTable() throws Exception { DataStore store = new DataStore( new Schema() - .createTable("FOO", ImmutableList.singleton("a")) + .createTable("FOO", "a") ); UnresolvedTableReference raw = new UnresolvedTableReference("Foo"); assertEquals("Foo", raw.tableName()); Modified: trunk/mayfly/test/net/sourceforge/mayfly/datastore/constraint/ForeignKeyTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/datastore/constraint/ForeignKeyTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/datastore/constraint/ForeignKeyTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -19,9 +19,9 @@ DataStore store = new DataStore( new Schema() - .createTable("foo", ImmutableList.singleton("bar_id")) + .createTable("foo", "bar_id") - .createTable("bar", ImmutableList.singleton("id")) + .createTable("bar", "id") .addRow("bar", ImmutableList.singleton("id"), ValueList.singleton(new LongCell(5))) ); key.checkInsert(store, DataStore.ANONYMOUS_SCHEMA_NAME, "foo", @@ -53,10 +53,10 @@ DataStore store = new DataStore( new Schema() - .createTable("foo", ImmutableList.singleton("bar_id")) + .createTable("foo", "bar_id") .addRow("foo", ImmutableList.singleton("bar_id"), ValueList.singleton(new LongCell(5))) - .createTable("bar", ImmutableList.singleton("id")) + .createTable("bar", "id") .addRow("bar", ImmutableList.singleton("id"), ValueList.singleton(new LongCell(5))) .addRow("bar", ImmutableList.singleton("id"), ValueList.singleton(new LongCell(6))) ); Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -15,7 +15,7 @@ GroupByKeys keys = new GroupByKeys( new GroupItem(new Concatenate(new SingleColumn("a"), new QuotedString("'abc'")))); ResultRow row = new ResultRow().withColumn("foo", "a", NullCell.INSTANCE); - keys.resolve(row, Evaluator.NO_SUBSELECT_NEEDED); + keys = keys.resolve(row, Evaluator.NO_SUBSELECT_NEEDED); assertEquals(1, keys.size()); Expression expression = keys.get(0).expression(); Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromTableTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromTableTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/from/FromTableTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -9,14 +9,13 @@ import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.expression.SingleColumn; import net.sourceforge.mayfly.evaluation.select.StoreEvaluator; -import net.sourceforge.mayfly.util.ImmutableList; public class FromTableTest extends TestCase { public void testCaseSensitiveTableName() throws Exception { Options options = new Options(true); DataStore store = new DataStore( - new Schema().createTable("foo", ImmutableList.singleton("x"))); + new Schema().createTable("foo", "x")); try { new FromTable("Foo", "f") .dummyRow( @@ -35,7 +34,7 @@ public void testOptionsPassedToRows() throws Exception { Options options = new Options(true); DataStore store = new DataStore( - new Schema().createTable("foo", ImmutableList.singleton("x"))); + new Schema().createTable("foo", "x")); ResultRow dummyRow = new FromTable("foo", "f") .dummyRow( new StoreEvaluator(store, Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java 2008-05-18 01:45:09 UTC (rev 562) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java 2008-06-16 04:47:12 UTC (rev 563) @@ -1,6 +1,10 @@ package net.sourceforge.mayfly.evaluation.select; -import junit.framework.TestCase; +import static org.junit.Assert.*; + +import org.junit.Ignore; +import org.junit.Test; + import junitx.framework.ObjectAssert; import net.sourceforge.mayfly.datastore.Schema; @@ -24,8 +28,9 @@ import net.sourceforge.mayfly.util.L; import net.sourceforge.mayfly.util.MayflyAssert; -public class SelectTest extends TestCase { +public class SelectTest { + @Test public void testExecuteSimpleJoin() throws Exception { ImmutableList fooColumns = new L().append("colA").append("colB").asImmutable(); ImmutableList barColumns = new L().append("colX").append("colY").asImmutable(); @@ -84,14 +89,15 @@ return optimized.query(); } + @Test public void testSmallerJoin() throws Exception { Evaluator evaluator = new StoreEvaluator( new Schema() - .createTable("foo", new L().append("colA")) + .createTable("foo", "colA") .addRow("foo", new ImmutableList().with("colA"), ValueList.singleton(new StringCell("1a"))) - .createTable("bar", new L().append("colX")) + .createTable("bar", "colX") .addRow("bar", new ImmutableList().with("colX"), ValueList.singleton(new StringCell("barXValue"))) ); @@ -100,6 +106,7 @@ assertRow("foo", "colA", "1a", "bar", "colX", "barXValue", rows.singleRow()); } + @Test public void testSimpleWhere() throws Exception { ImmutableList columnNames = new ImmutableList().with("colA").with("colB"); Evaluator evaluator = @@ -123,20 +130,33 @@ .with(new Value(new StringCell(secondStringValue))); } + @Test public void testMakeJoinsExplicit() throws Exception { Select select = (Select) Select.fromSql("select * from foo, bar"); - OptimizedSelect planned = select.planner().planForTests(); + OptimizedSelect planned = select.plan( + new StoreEvaluator(new Schema() + .createTable("foo") + .createTable("bar") + )); + InnerJoin join = (InnerJoin) planned.from; assertEquals("foo", ((FromTable) join.left).tableName); assertEquals("bar", ((FromTable) join.right).tableName); } + @Test public void testLeftAssociative() throws Exception { // At least for now, we don't try to pick the optimal order of // joins; we just take the listed order in a left-associative way. Select select = (Select) Select.fromSql("select * from foo, bar, baz"); - OptimizedSelect planned = select.planner().planForTests(); + OptimizedSelect planned = select.plan( + new StoreEvaluator(new Schema() + .createTable("foo") + .createTable("bar") + .createTable("baz") + )); + InnerJoin join = (InnerJoin) planned.from; InnerJoin firstJoin = (InnerJoin) join.left; @@ -146,14 +166,15 @@ assertEquals("baz", ((FromTable) join.right).tableName); } + @Test public void testTransformWhereToOn() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz where foo.id = bar.id"); OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("id")) - .createTable("bar", ImmutableList.singleton("id")) - .createTable("baz", ImmutableList.singleton("id")) + .createTable("foo", "id") + .createTable("bar", "id") + .createTable("baz", "id") )); InnerJoin join = (InnerJoin) planned.from; @@ -166,6 +187,29 @@ ObjectAssert.assertInstanceOf(True.class, planned.where); } + @Ignore + @Test + public void testAlsoWillTransformWhereToOnForExplicitJoin() throws Exception { + Select select = (Select) Select.fromSql( + "select * from (foo cross join bar) cross join baz where foo.id = bar.id"); + OptimizedSelect planned = select.plan( + new StoreEvaluator(new Schema() + .createTable("foo", "id") + .createTable("bar", "id") + .createTable("baz", "id") + )); + + InnerJoin join = (InnerJoin) planned.from; + InnerJoin firstJoin = (InnerJoin) join.left; + + Equal on = (Equal) firstJoin.condition; + MayflyAssert.assertColumn("foo", "id", on.leftSide); + MayflyAssert.assertColumn("bar", "id", on.rightSide); + + ObjectAssert.assertInstanceOf(True.class, planned.where); + } + + @Test public void testCanMove() throws Exception { assertTrue(Planner.canMove( new Equal( @@ -173,11 +217,12 @@ new SingleColumn("b")), new FromTable("foo"), new FromTable("bar"), new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("a")) - .createTable("bar", ImmutableList.singleton("b"))) + .createTable("foo", "a") + .createTable("bar", "b")) )); } + @Test public void testCannotMoveNoColumn() throws Exception { assertFalse(Planner.canMove( new Equal( @@ -185,11 +230,12 @@ new SingleColumn("c")), new FromTable("foo"), new FromTable("bar"), new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("a")) - .createTable("bar", ImmutableList.singleton("b"))) + .createTable("foo", "a") + .createTable("bar", "b")) )); } + @Test public void testCannotMoveNoTable() throws Exception { assertFalse(Planner.canMove( new Equal( @@ -197,11 +243,12 @@ new SingleColumn("baz", "c")), new FromTable("foo"), new FromTable("bar"), new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("a")) - .createTable("bar", ImmutableList.singleton("b"))) + .createTable("foo", "a") + .createTable("bar", "b")) )); } + @Test public void testCheckComplexExpressionUnmovable() throws Exception { assertFalse(Planner.canMove( new Or( @@ -212,11 +259,12 @@ ), new FromTable("foo"), new FromTable("bar"), new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("a")) - .createTable("bar", ImmutableList.singleton("b"))) + .createTable("foo", "a") + .createTable("bar", "b")) )); } + @Test public void testCheckComplexExpressionMovable() throws Exception { assertTrue(Planner.canMove( new Or( @@ -227,11 +275,12 @@ ), new FromTable("foo"), new FromTable("bar"), new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("a")) - .createTable("bar", ImmutableList.singleton("b"))) + .createTable("foo", "a") + .createTable("bar", "b")) )); } + @Test public void testCannotMoveAggregate() throws Exception { // The problem is that we don't yet have fully functional // machinery for taking max(a) and knowing that "a" is @@ -242,34 +291,36 @@ new IntegerLiteral(5)), new FromTable("foo"), new FromTable("bar"), new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("a")) - .createTable("bar", ImmutableList.singleton("b"))) + .createTable("foo", "a") + .createTable("bar", "b")) )); } + @Test public void testFullDummyRow() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz"); ResultRow dummyRow = select.planner().dummyRow( 0, new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("id")) - .createTable("bar", ImmutableList.singleton("id")) - .createTable("baz", ImmutableList.singleton("id")) + .createTable("foo", "id") + .createTable("bar", "id") + .createTable("baz", "id") )); assertEquals(3, dummyRow.size()); MayflyAssert.assertColumn("foo", "id", dummyRow.expression(0)); } + @Test public void testMoveLeftSideOfAnd() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz " + "where foo.id = bar.id and (bar.id = 5 or baz.id = 7)"); OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("id")) - .createTable("bar", ImmutableList.singleton("id")) - .createTable("baz", ImmutableList.singleton("id")) + .createTable("foo", "id") + .createTable("bar", "id") + .createTable("baz", "id") )); InnerJoin join = (InnerJoin) planned.from; @@ -288,15 +339,16 @@ ObjectAssert.assertInstanceOf(True.class, planned.where); } + @Test public void testMoveRightSideOfAnd() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz " + "where foo.id = baz.id and (bar.id = 5 or foo.id = 7)"); OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("id")) - .createTable("bar", ImmutableList.singleton("id")) - .createTable("baz", ImmutableList.singleton("id")) + .createTable("foo", "id") + .createTable("bar", "id") + .createTable("baz", "id") )); InnerJoin join = (InnerJoin) planned.from; @@ -313,15 +365,16 @@ ObjectAssert.assertInstanceOf(True.class, planned.where); } + @Test public void testMoveAlmostEverything() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz " + "where foo.id = bar.id and bar.id > 5 and baz.id = 9 and foo.id > 7"); OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() - .createTable("foo", ImmutableList.singleton("id")) - .createTable("bar", ImmutableList.singleton("id")) - .createTable("baz", ImmutableList.singleton("id")) + .createTable("foo", "id") + .createTable("bar", "id") + .createTable("baz", "id") )); InnerJoin join = (InnerJoin) planned.from; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-05-18 01:45:11
|
Revision: 562 http://mayfly.svn.sourceforge.net/mayfly/?rev=562&view=rev Author: kingdon Date: 2008-05-17 18:45:09 -0700 (Sat, 17 May 2008) Log Message: ----------- Include constraint name when a primary key or unique constraint fails. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/datastore/constraint/NotNullOrUnique.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/PrimaryKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropUniqueConstraintTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/constraint/NotNullOrUnique.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/constraint/NotNullOrUnique.java 2008-05-12 04:11:38 UTC (rev 561) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/constraint/NotNullOrUnique.java 2008-05-18 01:45:09 UTC (rev 562) @@ -102,7 +102,15 @@ private String constraintName(TableReference table) { StringBuilder message = new StringBuilder(); message.append(description()); - message.append(" in table "); + if (constraintName != null) { + message.append(" "); + message.append(constraintName); + message.append(" ("); + } + else { + message.append(" in "); + } + message.append("table "); message.append(table.tableName()); message.append(", column"); if (names.size() != 1) { @@ -118,6 +126,10 @@ message.append(","); message.append(column); } + + if (constraintName != null) { + message.append(")"); + } return message.toString(); } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/PrimaryKeyTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/PrimaryKeyTest.java 2008-05-12 04:11:38 UTC (rev 561) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/PrimaryKeyTest.java 2008-05-18 01:45:09 UTC (rev 562) @@ -74,9 +74,7 @@ execute("insert into foo(x) values(5)"); expectExecuteFailure("insert into foo(x) values(5)", - dialect.wishThisWereTrue() ? - "primary key my_primary_key (table foo, column x): duplicate value 5" : - "primary key in table foo, column x: duplicate value 5"); + "primary key my_primary_key (table foo, column x): duplicate value 5"); } public void testNotNull() throws Exception { Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropUniqueConstraintTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropUniqueConstraintTest.java 2008-05-12 04:11:38 UTC (rev 561) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropUniqueConstraintTest.java 2008-05-18 01:45:09 UTC (rev 562) @@ -13,7 +13,7 @@ execute("insert into foo(x, y) values(5, 'first')"); String insertSecond = "insert into foo(x, y) values(5, 'second')"; expectExecuteFailure(insertSecond, - "unique constraint in table foo, column x: duplicate value 5"); + "unique constraint x_uniq (table foo, column x): duplicate value 5"); String dropConstraint = "alter table foo drop constraint x_uniq"; if (dialect.haveDropConstraint()) { @@ -43,7 +43,7 @@ execute("insert into foo(x, y) values(5, 'first')"); String insertSecond = "insert into foo(x, y) values(5, 'second')"; expectExecuteFailure(insertSecond, - "unique constraint in table foo, column x: duplicate value 5"); + "unique constraint x_uniq (table foo, column x): duplicate value 5"); String sql = dropIndexCommand("x_uniq", "foo"); if (dialect.haveDropConstraint()) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-05-12 04:11:40
|
Revision: 561 http://mayfly.svn.sourceforge.net/mayfly/?rev=561&view=rev Author: kingdon Date: 2008-05-11 21:11:38 -0700 (Sun, 11 May 2008) Log Message: ----------- Go most of the way to making Select immutable by moving the mutating stuff to a mutable class Planner (for the process formerly known as optimizing). Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/datastore/ColumnNames.java trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/Insert.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/From.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java Added Paths: ----------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/IsDistinct.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/NotDistinct.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/ColumnNames.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/ColumnNames.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/ColumnNames.java 2008-05-12 04:11:38 UTC (rev 561) @@ -32,12 +32,29 @@ public static ColumnNames singleton(String column) { return new ColumnNames(ImmutableList.singleton(column)); } + + /** + * @internal + * @param names list of column names, or null to use all columns in + * the table, in the order specified by the table. + */ + public static ColumnNames fromParser( + DataStore store, TableReference table, ImmutableList<String> names) { + return + names != null ? + new ColumnNames(names) : + new ColumnNames(store.table(table).columnNames()); + } private final ImmutableList<String> names; public ColumnNames(ImmutableList<String> names) { this.names = names; } + + public ImmutableList<String> asList() { + return names; + } public int size() { return names.size(); Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java 2008-05-12 04:11:38 UTC (rev 561) @@ -116,17 +116,15 @@ public DataStore addRow(TableReference table, ImmutableList columnNames, ValueList values, Checker checker) { + if (columnNames == null) { + throw new NullPointerException("should have looked up column names by now"); + } + return replace(table.schema(), schema(table.schema()) .addRow(checker, table, columnNames, values)); } - public DataStore addRow(TableReference table, ValueList values, Checker checker) { - return replace(table.schema(), - schema(table.schema()) - .addRow(checker, table, values)); - } - public Set schemas() { Set names = new TreeSet(); for (Iterator iter = schemas.keySet().iterator(); iter.hasNext();) { Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java 2008-05-12 04:11:38 UTC (rev 561) @@ -159,13 +159,6 @@ columnNames, values); } - public Schema addRow(Checker checker, TableReference table, ValueList values) { - return new Schema( - tables.with( - lookUpTable(table.tableName()), - table(table.tableName()).addRow(checker, table, values))); - } - public UpdateSchema update(Checker checker, TableReference table, List setClauses, Condition where) { UpdateTable result = Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java 2008-05-12 04:11:38 UTC (rev 561) @@ -74,10 +74,6 @@ newColumns, constraints, rows.with(newRow), indexes); } - public TableData addRow(Checker checker, TableReference table, ValueList values) { - return addRow(checker, table, columns.asNames(), values); - } - public void checkColumnCount(ImmutableList<String> columnNames, ValueList values) { if (columnNames.size() != values.size()) { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/Insert.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/Insert.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/Insert.java 2008-05-12 04:11:38 UTC (rev 561) @@ -1,5 +1,6 @@ package net.sourceforge.mayfly.evaluation.command; +import net.sourceforge.mayfly.datastore.ColumnNames; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.datastore.TableReference; import net.sourceforge.mayfly.evaluation.Checker; @@ -11,7 +12,7 @@ public class Insert extends Command { public final UnresolvedTableReference table; - public final ImmutableList columnNames; + public final ImmutableList<String> columnNames; public final ValueList values; public final Location location; @@ -32,22 +33,13 @@ public UpdateStore update(DataStore store, String defaultSchema) { TableReference resolved = table.resolve(store, defaultSchema, null); Checker checker = new RealChecker(store, resolved, location, table.options); + ColumnNames columns = ColumnNames.fromParser(store, resolved, columnNames); return new UpdateStore( - addOneRow(store, resolved, columnNames, values, checker), + store.addRow(resolved, columns.asList(), values, checker), 1, checker.newIdentityValue() ); } - public static DataStore addOneRow(DataStore store, TableReference table, - ImmutableList columnNames, ValueList values, Checker checker) { - if (columnNames == null) { - return store.addRow(table, values, checker); - } - else { - return store.addRow(table, columnNames, values, checker); - } - } - } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java 2008-05-12 04:11:38 UTC (rev 561) @@ -3,6 +3,7 @@ import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.MayflyInternalException; import net.sourceforge.mayfly.MayflyResultSet; +import net.sourceforge.mayfly.datastore.ColumnNames; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.datastore.TableReference; import net.sourceforge.mayfly.evaluation.Checker; @@ -21,7 +22,7 @@ public class SubselectedInsert extends Command { private final UnresolvedTableReference unresolvedTable; - private final ImmutableList columnNames; + private final ImmutableList<String> columnNames; private final Location location; private final Select subselect; @@ -57,16 +58,15 @@ Checker checker) { DataStore store = evaluator.store(); - OptimizedSelect optimized = subselect.makeOptimized(evaluator); + OptimizedSelect optimized = subselect.plan(evaluator); - ImmutableList<String> names = - columnNames != null ? columnNames : store.table(table).columnNames(); - checkColumnCount(names, optimized.selected); + ColumnNames names = ColumnNames.fromParser(store, table, columnNames); + checkColumnCount(names.asList(), optimized.selected); MayflyResultSet rows = optimized.asResultSet(); while (rows.next()) { ValueList values = rows.asValues(subselect.location); - store = Insert.addOneRow(store, table, columnNames, values, checker); + store = store.addRow(table, names.asList(), values, checker); } return store; } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/From.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/From.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/from/From.java 2008-05-12 04:11:38 UTC (rev 561) @@ -7,7 +7,7 @@ public class From { - private final ImmutableList fromElements; + private final ImmutableList<FromElement> fromElements; public From(FromElement... elements) { this.fromElements = ImmutableList.fromArray(elements); @@ -36,7 +36,7 @@ public FromElement soleElement() { if (size() != 1) { throw new MayflyInternalException( - "optimizer left us " + size() + " elements"); + "planner left us " + size() + " elements"); } return element(0); @@ -47,7 +47,7 @@ } public FromElement element(int index) { - return (FromElement) fromElements.get(index); + return fromElements.get(index); } } Added: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java (rev 0) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Distinct.java 2008-05-12 04:11:38 UTC (rev 561) @@ -0,0 +1,10 @@ +package net.sourceforge.mayfly.evaluation.select; + +import net.sourceforge.mayfly.evaluation.ResultRows; +import net.sourceforge.mayfly.evaluation.what.Selected; + +public abstract class Distinct { + + abstract public ResultRows distinct(Selected selected, ResultRows rows); + +} Added: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/IsDistinct.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/IsDistinct.java (rev 0) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/IsDistinct.java 2008-05-12 04:11:38 UTC (rev 561) @@ -0,0 +1,38 @@ +package net.sourceforge.mayfly.evaluation.select; + +import net.sourceforge.mayfly.evaluation.GroupByCells; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.ResultRows; +import net.sourceforge.mayfly.evaluation.what.Selected; + +import java.util.LinkedHashSet; +import java.util.Set; + +public class IsDistinct extends Distinct { + + @Override + public ResultRows distinct(Selected selected, ResultRows rows) { + Set distinctRows = constructDistinctRows(selected, rows); + + return distinctRowsToResultRows(selected, distinctRows); + } + + private ResultRows distinctRowsToResultRows( + Selected selected, Set<GroupByCells> distinctRows) { + ResultRows result = new ResultRows(); + for (GroupByCells cells : distinctRows) { + result = result.with(selected.toRow(cells)); + } + return result; + } + + private Set constructDistinctRows(Selected selected, ResultRows rows) { + Set distinctRows = new LinkedHashSet(); + for (ResultRow row : rows) { + GroupByCells cells = selected.evaluateAll(row); + distinctRows.add(cells); + } + return distinctRows; + } + +} Added: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/NotDistinct.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/NotDistinct.java (rev 0) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/NotDistinct.java 2008-05-12 04:11:38 UTC (rev 561) @@ -0,0 +1,13 @@ +package net.sourceforge.mayfly.evaluation.select; + +import net.sourceforge.mayfly.evaluation.ResultRows; +import net.sourceforge.mayfly.evaluation.what.Selected; + +public class NotDistinct extends Distinct { + + @Override + public ResultRows distinct(Selected selected, ResultRows rows) { + return rows; + } + +} Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java 2008-05-12 04:11:38 UTC (rev 561) @@ -5,7 +5,6 @@ import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.ResultRows; import net.sourceforge.mayfly.evaluation.condition.Condition; -import net.sourceforge.mayfly.evaluation.from.From; import net.sourceforge.mayfly.evaluation.from.FromElement; import net.sourceforge.mayfly.evaluation.what.Selected; import net.sourceforge.mayfly.evaluation.what.What; @@ -16,17 +15,17 @@ public final Selected selected; private final ResultRow dummyRow; - private final From from; - private final Condition where; + public final FromElement from; + final Condition where; private final Aggregator groupBy; - private final boolean distinct; + private final Distinct distinct; private final OrderBy orderBy; private final What what; private final Limit limit; public OptimizedSelect( Evaluator evaluator, Selected selected, ResultRow dummyRow, - From from, Condition where, Aggregator groupBy, boolean distinct, + FromElement from, Condition where, Aggregator groupBy, Distinct distinct, OrderBy orderBy, What what, Limit limit) { this.evaluator = evaluator; this.selected = selected; @@ -41,14 +40,13 @@ } ResultRows query() { - FromElement element = from.soleElement(); - ResultRows joinedRows = element.tableContents(evaluator); + ResultRows joinedRows = from.tableContents(evaluator); ResultRows afterWhere = joinedRows.select(where, evaluator); ResultRows afterGrouping = groupBy.group(afterWhere, evaluator, selected); - ResultRows afterDistinct = Select.distinct(selected, afterGrouping, distinct); + ResultRows afterDistinct = distinct.distinct(selected, afterGrouping); ResultRows sorted = orderBy.sort(afterDistinct, what, evaluator); return limit.limit(sorted); Added: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java (rev 0) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Planner.java 2008-05-12 04:11:38 UTC (rev 561) @@ -0,0 +1,204 @@ +package net.sourceforge.mayfly.evaluation.select; + +import java.util.Iterator; + +import net.sourceforge.mayfly.MayflyException; +import net.sourceforge.mayfly.datastore.DataStore; +import net.sourceforge.mayfly.evaluation.Aggregator; +import net.sourceforge.mayfly.evaluation.Expression; +import net.sourceforge.mayfly.evaluation.NoColumn; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.ResultRows; +import net.sourceforge.mayfly.evaluation.condition.And; +import net.sourceforge.mayfly.evaluation.condition.Condition; +import net.sourceforge.mayfly.evaluation.condition.True; +import net.sourceforge.mayfly.evaluation.from.From; +import net.sourceforge.mayfly.evaluation.from.FromElement; +import net.sourceforge.mayfly.evaluation.from.InnerJoin; +import net.sourceforge.mayfly.evaluation.what.Selected; +import net.sourceforge.mayfly.evaluation.what.What; + +/* At least currently, this is written as a mutable object. It is a short-lived + one. */ +public class Planner { + + private final What what; + + // mutated as we make joins explicit + private From from; + + // mutated as we move conditions from WHERE to ON + private Condition where; + + private final Aggregator groupBy; + private final Distinct distinct; + private final OrderBy orderBy; + private final Limit limit; + + public Planner(What what, From from, Condition where, Aggregator groupBy, + Distinct distinct, OrderBy orderBy, Limit limit) { + this.what = what; + this.from = from; + this.where = where; + this.groupBy = groupBy; + this.distinct = distinct; + this.orderBy = orderBy; + this.limit = limit; + } + + public OptimizedSelect planForTests() { + optimize(); + return new OptimizedSelect( + null, null, null, + from.soleElement(), where, groupBy, distinct, orderBy, what, limit); + } + + public OptimizedSelect plan(Evaluator evaluator) { + Evaluator aliasEvaluator = new AliasEvaluator(what, evaluator); + + optimize(aliasEvaluator); + ResultRow dummyRow = dummyRow(aliasEvaluator); + Selected selected = what.selected(dummyRow); + + check(aliasEvaluator, selected, dummyRow); + return new OptimizedSelect( + aliasEvaluator, selected, dummyRow, + from.soleElement(), where, groupBy, distinct, orderBy, what, limit); + } + + private void check(Evaluator evaluator, Selected selected, ResultRow dummyRow) { + for (Iterator iter = selected.iterator(); iter.hasNext();) { + Expression element = (Expression) iter.next(); + element.evaluate(dummyRow, evaluator); + } + + where.evaluate(dummyRow, evaluator); + where.rejectAggregates("WHERE"); + ResultRow groupedDummyRow = groupBy.check(dummyRow, evaluator, selected); + + ResultRows afterDistinct = + distinct.distinct(selected, new ResultRows(groupedDummyRow)); + + orderBy.check(afterDistinct.singleRow(), groupedDummyRow, + dummyRow, evaluator); + + if (orderBy.isEmpty() && limit.isSpecified()) { + throw new MayflyException("Must specify ORDER BY with LIMIT"); + } + } + + private ResultRow dummyRow(Evaluator evaluator) { + FromElement element = from.soleElement(); + return element.dummyRow(evaluator); + } + + public void optimize() { + optimize(null); + } + + /** + * Currently this method makes joins explicit and also moves + * conditions from WHERE to ON. The whole thing would probably + * be cleaner if those were separated. The second step + * would be optional (for those tests currently passing in + * null for store) and the {@link #dummyRow(int, DataStore, String)} + * method could make use of the joins which were built up + * in the first step. + */ + public void optimize(Evaluator evaluator) { + if (evaluator != null) { + ResultRow fullDummyRow = dummyRow(0, evaluator); + where.evaluate(fullDummyRow, evaluator); + } + + while (from.size() > 1) { + // x y z -> join(x, y) z + FromElement first = from.element(0); + FromElement second = from.element(1); + + Condition on = + moveWhereToOn(first, second, evaluator); + InnerJoin explicitJoin = new InnerJoin(first, second, on); + + from = from.without(0).without(0).with(0, explicitJoin); + } + } + + ResultRow dummyRow(int index, Evaluator evaluator) { + ResultRow dummyRow = from.element(index).dummyRow(evaluator); + if (index >= from.size() - 1) { + return dummyRow; + } + else { + return dummyRow.combine( + dummyRow(index + 1, evaluator)); + } + } + + private Condition moveWhereToOn( + FromElement first, FromElement second, + Evaluator evaluator) { + if (evaluator == null) { + // For convenience in tests. + return Condition.TRUE; + } + + MoveResult result = new MoveResult(); + moveToResult(first, second, evaluator, result, where); + where = result.nonMovable; + return result.toBeMoved; + } + + private void moveToResult(FromElement first, FromElement second, + Evaluator evaluator, + final MoveResult moveResult, Condition toAnalyze) { + if (canMove(toAnalyze, first, second, evaluator)) { + moveResult.toBeMoved = makeAnd(toAnalyze, moveResult.toBeMoved); + } + else if (toAnalyze instanceof And) { + And and = (And) toAnalyze; + moveToResult(first, second, evaluator, moveResult, and.leftSide); + moveToResult(first, second, evaluator, moveResult, and.rightSide); + } + else { + moveResult.nonMovable = toAnalyze; + } + } + + private Condition makeAnd(Condition left, Condition right) { + // Turn "foo and true" into "foo" (mainly to make unit tests easier). + if (left instanceof True) { + return right; + } + else if (right instanceof True) { + return left; + } + else { + return new And(left, right); + } + } + + static class MoveResult { + Condition toBeMoved = Condition.TRUE; + Condition nonMovable = Condition.TRUE; + } + + static boolean canMove(Condition condition, + FromElement first, FromElement second, + Evaluator evaluator) { + if (condition.firstAggregate() != null) { + return false; + } + + InnerJoin join = new InnerJoin(first, second, Condition.TRUE); + ResultRow partialDummyRow = join.dummyRow(evaluator); + try { + condition.check(partialDummyRow); + return true; + } + catch (NoColumn e) { + return false; + } + } + +} Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java 2008-05-12 04:11:38 UTC (rev 561) @@ -5,45 +5,28 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.evaluation.Aggregator; -import net.sourceforge.mayfly.evaluation.Expression; -import net.sourceforge.mayfly.evaluation.GroupByCells; import net.sourceforge.mayfly.evaluation.GroupByKeys; -import net.sourceforge.mayfly.evaluation.NoColumn; -import net.sourceforge.mayfly.evaluation.ResultRow; -import net.sourceforge.mayfly.evaluation.ResultRows; import net.sourceforge.mayfly.evaluation.command.Command; import net.sourceforge.mayfly.evaluation.command.UpdateStore; -import net.sourceforge.mayfly.evaluation.condition.And; import net.sourceforge.mayfly.evaluation.condition.Condition; -import net.sourceforge.mayfly.evaluation.condition.True; import net.sourceforge.mayfly.evaluation.from.From; -import net.sourceforge.mayfly.evaluation.from.FromElement; -import net.sourceforge.mayfly.evaluation.from.InnerJoin; -import net.sourceforge.mayfly.evaluation.what.Selected; import net.sourceforge.mayfly.evaluation.what.What; import net.sourceforge.mayfly.parser.Location; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - public class Select extends Command { private final What what; - /** - * Can't yet be final, because of {@link #optimize(Evaluator)}. - */ - private /*final*/ From from; + private final From from; - public Condition where; + private final Condition where; /** * Not immutable, because of {@link GroupByKeys} */ private final Aggregator groupBy; - private final boolean distinct; + private final Distinct distinct; private final OrderBy orderBy; @@ -57,202 +40,29 @@ this.from = from; this.where = where; this.groupBy = groupBy; - this.distinct = distinct; + this.distinct = distinct ? new IsDistinct() : new NotDistinct(); this.orderBy = orderBy; this.limit = limit; this.location = location; } - public From from() { - return from; - } - @Override public MayflyResultSet select(Evaluator evaluator, Cell lastIdentity) { - return makeOptimized(evaluator).asResultSet(); + return plan(evaluator).asResultSet(); } - - public OptimizedSelect makeOptimized(Evaluator evaluator) { - Evaluator aliasEvaluator = new AliasEvaluator(what, evaluator); - - optimize(aliasEvaluator); - ResultRow dummyRow = dummyRow(aliasEvaluator); - Selected selected = what.selected(dummyRow); - - check(aliasEvaluator, selected, dummyRow); - return new OptimizedSelect( - aliasEvaluator, selected, dummyRow, - from, where, groupBy, distinct, orderBy, what, limit); - } - - private void check(Evaluator evaluator, Selected selected, ResultRow dummyRow) { - for (Iterator iter = selected.iterator(); iter.hasNext();) { - Expression element = (Expression) iter.next(); - element.evaluate(dummyRow, evaluator); - } - - where.evaluate(dummyRow, evaluator); - where.rejectAggregates("WHERE"); - ResultRow groupedDummyRow = groupBy.check(dummyRow, evaluator, selected); - - ResultRows afterDistinct = - distinct(selected, new ResultRows(groupedDummyRow), distinct); - - orderBy.check(afterDistinct.singleRow(), groupedDummyRow, - dummyRow, evaluator); - - if (orderBy.isEmpty() && limit.isSpecified()) { - throw new MayflyException("Must specify ORDER BY with LIMIT"); - } - } - - private ResultRow dummyRow(Evaluator evaluator) { - FromElement element = from.soleElement(); - return element.dummyRow(evaluator); - } - - public static ResultRows distinct(Selected selected, ResultRows rows, boolean isDistinct) { - if (!isDistinct) { - return rows; - } - - Set distinctRows = constructDistinctRows(selected, rows); - - return distinctRowsToResultRows(selected, distinctRows); - } - - private static ResultRows distinctRowsToResultRows(Selected selected, Set distinctRows) { - ResultRows result = new ResultRows(); - for (Iterator iter = distinctRows.iterator(); iter.hasNext();) { - GroupByCells cells = (GroupByCells) iter.next(); - result = result.with(selected.toRow(cells)); - } - return result; - } - - private static Set constructDistinctRows(Selected selected, ResultRows rows) { - Set distinctRows = new LinkedHashSet(); - for (Iterator iter = rows.iterator(); iter.hasNext();) { - ResultRow row = (ResultRow) iter.next(); - GroupByCells cells = selected.evaluateAll(row); - distinctRows.add(cells); - } - return distinctRows; - } - + @Override public UpdateStore update(DataStore store, String schema) { throw new MayflyException( "SELECT is only available with query, not update"); } - public void optimize() { - optimize(null); + public OptimizedSelect plan(Evaluator evaluator) { + return planner().plan(evaluator); } - /** - * Currently this method makes joins explicit and also moves - * conditions from WHERE to ON. The whole thing would probably - * be cleaner if those were separated. The second step - * would be optional (for those tests currently passing in - * null for store) and the {@link #dummyRow(int, DataStore, String)} - * method could make use of the joins which were built up - * in the first step. - */ - public void optimize(Evaluator evaluator) { - if (evaluator != null) { - ResultRow fullDummyRow = dummyRow(0, evaluator); - where.evaluate(fullDummyRow, evaluator); - } - - while (from.size() > 1) { - // x y z -> join(x, y) z - FromElement first = from.element(0); - FromElement second = from.element(1); - - Condition on = - moveWhereToOn(first, second, evaluator); - InnerJoin explicitJoin = new InnerJoin(first, second, on); - - from = from.without(0).without(0).with(0, explicitJoin); - } + public Planner planner() { + return new Planner(what, from, where, groupBy, distinct, orderBy, limit); } - ResultRow dummyRow(int index, Evaluator evaluator) { - ResultRow dummyRow = from.element(index).dummyRow(evaluator); - if (index >= from.size() - 1) { - return dummyRow; - } - else { - return dummyRow.combine( - dummyRow(index + 1, evaluator)); - } - } - - private Condition moveWhereToOn( - FromElement first, FromElement second, - Evaluator evaluator) { - if (evaluator == null) { - // For convenience in tests. - return Condition.TRUE; - } - - MoveResult result = new MoveResult(); - moveToResult(first, second, evaluator, result, where); - where = result.nonMovable; - return result.toBeMoved; - } - - private void moveToResult(FromElement first, FromElement second, - Evaluator evaluator, - final MoveResult moveResult, Condition toAnalyze) { - if (canMove(toAnalyze, first, second, evaluator)) { - moveResult.toBeMoved = makeAnd(toAnalyze, moveResult.toBeMoved); - } - else if (toAnalyze instanceof And) { - And and = (And) toAnalyze; - moveToResult(first, second, evaluator, moveResult, and.leftSide); - moveToResult(first, second, evaluator, moveResult, and.rightSide); - } - else { - moveResult.nonMovable = toAnalyze; - } - } - - private Condition makeAnd(Condition left, Condition right) { - // Turn "foo and true" into "foo" (mainly to make unit tests easier). - if (left instanceof True) { - return right; - } - else if (right instanceof True) { - return left; - } - else { - return new And(left, right); - } - } - - static class MoveResult { - Condition toBeMoved = Condition.TRUE; - Condition nonMovable = Condition.TRUE; - } - - static boolean canMove(Condition condition, - FromElement first, FromElement second, - Evaluator evaluator) { - if (condition.firstAggregate() != null) { - return false; - } - - InnerJoin join = new InnerJoin(first, second, Condition.TRUE); - ResultRow partialDummyRow = join.dummyRow(evaluator); - try { - condition.check(partialDummyRow); - return true; - } - catch (NoColumn e) { - return false; - } - } - } Modified: trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java 2008-05-12 04:11:38 UTC (rev 561) @@ -19,13 +19,4 @@ assertEquals(1, newStore.table("mars", "foo").rowCount()); } - public void testAddRowWithSchemaNoColumnNames() throws Exception { - DataStore store = new DataStore() - .addSchema("mars", new Schema().createTable("foo", Collections.singletonList("x"))); - DataStore newStore = store.addRow( - new TableReference("mars", "foo"), - ValueList.singleton(new LongCell(5)), new NullChecker()); - assertEquals(1, newStore.table("mars", "foo").rowCount()); - } - } Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java 2008-05-10 02:11:28 UTC (rev 560) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java 2008-05-12 04:11:38 UTC (rev 561) @@ -80,7 +80,7 @@ private ResultRows query(Evaluator evaluator, String sql) { Select select = (Select) Command.fromSql(sql); - OptimizedSelect optimized = select.makeOptimized(evaluator); + OptimizedSelect optimized = select.plan(evaluator); return optimized.query(); } @@ -125,8 +125,8 @@ public void testMakeJoinsExplicit() throws Exception { Select select = (Select) Select.fromSql("select * from foo, bar"); - select.optimize(); - InnerJoin join = (InnerJoin) select.from().soleElement(); + OptimizedSelect planned = select.planner().planForTests(); + InnerJoin join = (InnerJoin) planned.from; assertEquals("foo", ((FromTable) join.left).tableName); assertEquals("bar", ((FromTable) join.right).tableName); @@ -136,8 +136,8 @@ // At least for now, we don't try to pick the optimal order of // joins; we just take the listed order in a left-associative way. Select select = (Select) Select.fromSql("select * from foo, bar, baz"); - select.optimize(); - InnerJoin join = (InnerJoin) select.from().soleElement(); + OptimizedSelect planned = select.planner().planForTests(); + InnerJoin join = (InnerJoin) planned.from; InnerJoin firstJoin = (InnerJoin) join.left; assertEquals("foo", ((FromTable) firstJoin.left).tableName); @@ -149,25 +149,25 @@ public void testTransformWhereToOn() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz where foo.id = bar.id"); - select.optimize( + OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() .createTable("foo", ImmutableList.singleton("id")) .createTable("bar", ImmutableList.singleton("id")) .createTable("baz", ImmutableList.singleton("id")) )); - InnerJoin join = (InnerJoin) select.from().soleElement(); + InnerJoin join = (InnerJoin) planned.from; InnerJoin firstJoin = (InnerJoin) join.left; Equal on = (Equal) firstJoin.condition; MayflyAssert.assertColumn("foo", "id", on.leftSide); MayflyAssert.assertColumn("bar", "id", on.rightSide); - ObjectAssert.assertInstanceOf(True.class, select.where); + ObjectAssert.assertInstanceOf(True.class, planned.where); } public void testCanMove() throws Exception { - assertTrue(Select.canMove( + assertTrue(Planner.canMove( new Equal( new SingleColumn("foo", "a"), new SingleColumn("b")), @@ -179,7 +179,7 @@ } public void testCannotMoveNoColumn() throws Exception { - assertFalse(Select.canMove( + assertFalse(Planner.canMove( new Equal( new SingleColumn("foo", "a"), new SingleColumn("c")), @@ -191,7 +191,7 @@ } public void testCannotMoveNoTable() throws Exception { - assertFalse(Select.canMove( + assertFalse(Planner.canMove( new Equal( new SingleColumn("foo", "a"), new SingleColumn("baz", "c")), @@ -203,7 +203,7 @@ } public void testCheckComplexExpressionUnmovable() throws Exception { - assertFalse(Select.canMove( + assertFalse(Planner.canMove( new Or( new Equal(new IntegerLiteral(5), new IntegerLiteral(5)), new Equal( @@ -218,7 +218,7 @@ } public void testCheckComplexExpressionMovable() throws Exception { - assertTrue(Select.canMove( + assertTrue(Planner.canMove( new Or( new Equal(new IntegerLiteral(5), new IntegerLiteral(5)), new Equal( @@ -236,7 +236,7 @@ // The problem is that we don't yet have fully functional // machinery for taking max(a) and knowing that "a" is // foo.a and not some other a. - assertFalse(Select.canMove( + assertFalse(Planner.canMove( new Equal( new Maximum(new SingleColumn("a"), "max", false), new IntegerLiteral(5)), @@ -250,7 +250,7 @@ public void testFullDummyRow() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz"); - ResultRow dummyRow = select.dummyRow( + ResultRow dummyRow = select.planner().dummyRow( 0, new StoreEvaluator(new Schema() .createTable("foo", ImmutableList.singleton("id")) @@ -265,14 +265,14 @@ Select select = (Select) Select.fromSql( "select * from foo, bar, baz " + "where foo.id = bar.id and (bar.id = 5 or baz.id = 7)"); - select.optimize( + OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() .createTable("foo", ImmutableList.singleton("id")) .createTable("bar", ImmutableList.singleton("id")) .createTable("baz", ImmutableList.singleton("id")) )); - InnerJoin join = (InnerJoin) select.from().soleElement(); + InnerJoin join = (InnerJoin) planned.from; InnerJoin firstJoin = (InnerJoin) join.left; Equal on = (Equal) firstJoin.condition; @@ -285,21 +285,21 @@ Equal bazEquals7 = (Equal) movedToLastJoin.rightSide; MayflyAssert.assertColumn("baz", "id", bazEquals7.leftSide); - ObjectAssert.assertInstanceOf(True.class, select.where); + ObjectAssert.assertInstanceOf(True.class, planned.where); } public void testMoveRightSideOfAnd() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz " + "where foo.id = baz.id and (bar.id = 5 or foo.id = 7)"); - select.optimize( + OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() .createTable("foo", ImmutableList.singleton("id")) .createTable("bar", ImmutableList.singleton("id")) .createTable("baz", ImmutableList.singleton("id")) )); - InnerJoin join = (InnerJoin) select.from().soleElement(); + InnerJoin join = (InnerJoin) planned.from; InnerJoin firstJoin = (InnerJoin) join.left; Or on = (Or) firstJoin.condition; @@ -310,21 +310,21 @@ MayflyAssert.assertColumn("foo", "id", movedToLastJoin.leftSide); MayflyAssert.assertColumn("baz", "id", movedToLastJoin.rightSide); - ObjectAssert.assertInstanceOf(True.class, select.where); + ObjectAssert.assertInstanceOf(True.class, planned.where); } public void testMoveAlmostEverything() throws Exception { Select select = (Select) Select.fromSql( "select * from foo, bar, baz " + "where foo.id = bar.id and bar.id > 5 and baz.id = 9 and foo.id > 7"); - select.optimize( + OptimizedSelect planned = select.plan( new StoreEvaluator(new Schema() .createTable("foo", ImmutableList.singleton("id")) .createTable("bar", ImmutableList.singleton("id")) .createTable("baz", ImmutableList.singleton("id")) )); - InnerJoin join = (InnerJoin) select.from().soleElement(); + InnerJoin join = (InnerJoin) planned.from; InnerJoin firstJoin = (InnerJoin) join.left; And on = (And) firstJoin.condition; @@ -336,7 +336,7 @@ Equal movedToLastJoin = (Equal) join.condition; MayflyAssert.assertColumn("baz", "id", movedToLastJoin.leftSide); - ObjectAssert.assertInstanceOf(True.class, select.where); + ObjectAssert.assertInstanceOf(True.class, planned.where); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-05-10 02:11:30
|
Revision: 560 http://mayfly.svn.sourceforge.net/mayfly/?rev=560&view=rev Author: kingdon Date: 2008-05-09 19:11:28 -0700 (Fri, 09 May 2008) Log Message: ----------- Fix bug whereby an error in the number of columns in an INSERT and its subselect would only be detected if there are rows. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ValueList.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/InsertSubselectTest.java trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java Added Paths: ----------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java 2008-05-10 02:11:28 UTC (rev 560) @@ -13,6 +13,7 @@ import net.sourceforge.mayfly.evaluation.condition.Condition; import net.sourceforge.mayfly.parser.Location; import net.sourceforge.mayfly.util.CaseInsensitiveString; +import net.sourceforge.mayfly.util.ImmutableList; import net.sourceforge.mayfly.util.ImmutableMap; import java.util.Iterator; @@ -114,7 +115,7 @@ } public DataStore addRow(TableReference table, - List columnNames, ValueList values, Checker checker) { + ImmutableList columnNames, ValueList values, Checker checker) { return replace(table.schema(), schema(table.schema()) .addRow(checker, table, columnNames, values)); Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java 2008-05-10 02:11:28 UTC (rev 560) @@ -148,12 +148,12 @@ } public Schema addRow(Checker checker, TableReference table, - List columnNames, ValueList values) { + ImmutableList columnNames, ValueList values) { return new Schema(tables.with(lookUpTable(table.tableName()), table(table.tableName()).addRow(checker, table, columnNames, values))); } - public Schema addRow(String table, List columnNames, ValueList values) { + public Schema addRow(String table, ImmutableList columnNames, ValueList values) { return addRow(new NullChecker(), new TableReference(DataStore.ANONYMOUS_SCHEMA_NAME, table), columnNames, values); Modified: trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/src/net/sourceforge/mayfly/datastore/TableData.java 2008-05-10 02:11:28 UTC (rev 560) @@ -42,20 +42,13 @@ } public TableData addRow(Checker checker, TableReference table, - List columnNames, ValueList values) { - if (columnNames.size() != values.size()) { - Columns columnsToInsert = findColumns(columnNames); - if (values.size() > columnNames.size()) { - throw makeException("Too many values.\n", columnsToInsert, values); - } else { - throw makeException("Too few values.\n", columnsToInsert, values); - } - } + ImmutableList<String> columnNames, ValueList values) { + checkColumnCount(columnNames, values); TupleMapper tuple = new TupleMapper(); Columns newColumns = columns; for (int i = 0; i < values.size(); ++i) { - String columnName = (String)columnNames.get(i); + String columnName = columnNames.get(i); Column column = columns.columnFromName(columnName); newColumns = addColumn(newColumns, tuple, column, checker, values.value(i)); @@ -85,12 +78,54 @@ return addRow(checker, table, columns.asNames(), values); } - private MayflyException makeException(String message, Columns columnsToInsert, ValueList values) { + public void checkColumnCount(ImmutableList<String> columnNames, + ValueList values) { + if (columnNames.size() != values.size()) { + if (values.size() > columnNames.size()) { + throw makeException("Too many values.\n", columnNames, values); + } else { + throw makeException("Too few values.\n", columnNames, values); + } + } + } + + private MayflyException makeException(String message, + ImmutableList<String> columnNames, ValueList values) { return new MayflyException( - message + describeNamesAndValues(columnsToInsert, values.asCells()), + message + describeNamesAndValues(columnNames, values), values.location); } + private String describeNamesAndValues( + ImmutableList<String> columns, ValueList values) { + StringBuilder result = new StringBuilder(); + + result.append("Columns and values were:\n"); + + Iterator<String> nameIterator = columns.iterator(); + Iterator<Cell> valueIterator = values.asCells().iterator(); + while (nameIterator.hasNext() || valueIterator.hasNext()) { + if (nameIterator.hasNext()) { + String columnName = nameIterator.next(); + result.append(columnName); + } else { + result.append("(none)"); + } + + result.append(' '); + + if (valueIterator.hasNext()) { + Cell value = valueIterator.next(); + result.append(value.toString()); + } else { + result.append("(none)"); + } + + result.append('\n'); + } + return result.toString(); + } + private Columns addColumn(Columns newColumns, TupleMapper tuple, Column column, Checker checker, Value value) { boolean isDefault = value.value == null; Cell cell = column.coerce( @@ -178,35 +213,6 @@ return new UpdateTable(newTable, rowsAffected); } - private String describeNamesAndValues(Columns columns, List values) { - StringBuilder result = new StringBuilder(); - - result.append("Columns and values were:\n"); - - Iterator nameIterator = columns.iterator(); - Iterator valueIterator = values.iterator(); - while (nameIterator.hasNext() || valueIterator.hasNext()) { - if (nameIterator.hasNext()) { - Column column = (Column) nameIterator.next(); - result.append(column.columnName()); - } else { - result.append("(none)"); - } - - result.append(' '); - - if (valueIterator.hasNext()) { - Object value = valueIterator.next(); - result.append(value.toString()); - } else { - result.append("(none)"); - } - - result.append('\n'); - } - return result.toString(); - } - public Columns findColumns(List columnNames) { L columnList = new L(); for (Iterator iter = columnNames.iterator(); iter.hasNext();) { @@ -235,7 +241,7 @@ return columns.columnFromName(columnName); } - public List columnNames() { + public ImmutableList<String> columnNames() { return columns.asNames(); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ValueList.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ValueList.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ValueList.java 2008-05-10 02:11:28 UTC (rev 560) @@ -34,7 +34,7 @@ return new ValueList(values, this.location.combine(end)); } - public ImmutableList asCells() { + public ImmutableList<Cell> asCells() { List cells = new ArrayList(); for (Iterator iter = values.iterator(); iter.hasNext();) { Value value = (Value) iter.next(); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/command/SubselectedInsert.java 2008-05-10 02:11:28 UTC (rev 560) @@ -1,17 +1,23 @@ package net.sourceforge.mayfly.evaluation.command; +import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.MayflyInternalException; import net.sourceforge.mayfly.MayflyResultSet; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.datastore.TableReference; import net.sourceforge.mayfly.evaluation.Checker; +import net.sourceforge.mayfly.evaluation.Expression; import net.sourceforge.mayfly.evaluation.RealChecker; import net.sourceforge.mayfly.evaluation.ValueList; import net.sourceforge.mayfly.evaluation.select.Evaluator; +import net.sourceforge.mayfly.evaluation.select.OptimizedSelect; import net.sourceforge.mayfly.evaluation.select.Select; +import net.sourceforge.mayfly.evaluation.what.Selected; import net.sourceforge.mayfly.parser.Location; import net.sourceforge.mayfly.util.ImmutableList; +import java.util.Iterator; + public class SubselectedInsert extends Command { private final UnresolvedTableReference unresolvedTable; @@ -51,7 +57,13 @@ Checker checker) { DataStore store = evaluator.store(); - MayflyResultSet rows = subselect.select(evaluator, null); + OptimizedSelect optimized = subselect.makeOptimized(evaluator); + + ImmutableList<String> names = + columnNames != null ? columnNames : store.table(table).columnNames(); + checkColumnCount(names, optimized.selected); + + MayflyResultSet rows = optimized.asResultSet(); while (rows.next()) { ValueList values = rows.asValues(subselect.location); store = Insert.addOneRow(store, table, columnNames, values, checker); @@ -59,4 +71,52 @@ return store; } + private void checkColumnCount(ImmutableList<String> columnNames, + Selected selected) { + if (columnNames.size() != selected.size()) { + if (selected.size() > columnNames.size()) { + throw makeException("Too many values.\n", columnNames, selected); + } else { + throw makeException("Too few values.\n", columnNames, selected); + } + } + } + + private MayflyException makeException(String message, + ImmutableList<String> columnNames, Selected selected) { + return new MayflyException( + message + describeNamesAndValues(columnNames, selected), + subselect.location); + } + + private String describeNamesAndValues( + ImmutableList<String> columns, Selected selected) { + StringBuilder result = new StringBuilder(); + + result.append("Columns and values from subselect were:\n"); + + Iterator<String> nameIterator = columns.iterator(); + Iterator<Expression> valueIterator = selected.iterator(); + while (nameIterator.hasNext() || valueIterator.hasNext()) { + if (nameIterator.hasNext()) { + String columnName = nameIterator.next(); + result.append(columnName); + } else { + result.append("(none)"); + } + + result.append(' '); + + if (valueIterator.hasNext()) { + Expression value = valueIterator.next(); + result.append(value.displayName()); + } else { + result.append("(none)"); + } + + result.append('\n'); + } + return result.toString(); + } + } Added: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java (rev 0) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/OptimizedSelect.java 2008-05-10 02:11:28 UTC (rev 560) @@ -0,0 +1,65 @@ +package net.sourceforge.mayfly.evaluation.select; + +import net.sourceforge.mayfly.MayflyResultSet; +import net.sourceforge.mayfly.evaluation.Aggregator; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.ResultRows; +import net.sourceforge.mayfly.evaluation.condition.Condition; +import net.sourceforge.mayfly.evaluation.from.From; +import net.sourceforge.mayfly.evaluation.from.FromElement; +import net.sourceforge.mayfly.evaluation.what.Selected; +import net.sourceforge.mayfly.evaluation.what.What; + +public class OptimizedSelect { + + private final Evaluator evaluator; + public final Selected selected; + private final ResultRow dummyRow; + + private final From from; + private final Condition where; + private final Aggregator groupBy; + private final boolean distinct; + private final OrderBy orderBy; + private final What what; + private final Limit limit; + + public OptimizedSelect( + Evaluator evaluator, Selected selected, ResultRow dummyRow, + From from, Condition where, Aggregator groupBy, boolean distinct, + OrderBy orderBy, What what, Limit limit) { + this.evaluator = evaluator; + this.selected = selected; + this.dummyRow = dummyRow; + this.from = from; + this.where = where; + this.groupBy = groupBy; + this.distinct = distinct; + this.orderBy = orderBy; + this.what = what; + this.limit = limit; + } + + ResultRows query() { + FromElement element = from.soleElement(); + ResultRows joinedRows = element.tableContents(evaluator); + + ResultRows afterWhere = joinedRows.select(where, evaluator); + + ResultRows afterGrouping = groupBy.group(afterWhere, evaluator, selected); + + ResultRows afterDistinct = Select.distinct(selected, afterGrouping, distinct); + + ResultRows sorted = orderBy.sort(afterDistinct, what, evaluator); + return limit.limit(sorted); + } + + public MayflyResultSet asResultSet() { + return new MayflyResultSet(selected, query()); + } + + public MayflyResultSet dummyResultSet() { + return new MayflyResultSet(selected, new ResultRows(dummyRow)); + } + +} Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Select.java 2008-05-10 02:11:28 UTC (rev 560) @@ -69,6 +69,10 @@ @Override public MayflyResultSet select(Evaluator evaluator, Cell lastIdentity) { + return makeOptimized(evaluator).asResultSet(); + } + + public OptimizedSelect makeOptimized(Evaluator evaluator) { Evaluator aliasEvaluator = new AliasEvaluator(what, evaluator); optimize(aliasEvaluator); @@ -76,8 +80,9 @@ Selected selected = what.selected(dummyRow); check(aliasEvaluator, selected, dummyRow); - ResultRows rows = query(aliasEvaluator, selected); - return new MayflyResultSet(selected, rows); + return new OptimizedSelect( + aliasEvaluator, selected, dummyRow, + from, where, groupBy, distinct, orderBy, what, limit); } private void check(Evaluator evaluator, Selected selected, ResultRow dummyRow) { @@ -91,7 +96,7 @@ ResultRow groupedDummyRow = groupBy.check(dummyRow, evaluator, selected); ResultRows afterDistinct = - distinct(selected, new ResultRows(groupedDummyRow)); + distinct(selected, new ResultRows(groupedDummyRow), distinct); orderBy.check(afterDistinct.singleRow(), groupedDummyRow, dummyRow, evaluator); @@ -106,23 +111,8 @@ return element.dummyRow(evaluator); } - ResultRows query(Evaluator evaluator, Selected selected) { - FromElement element = from.soleElement(); - ResultRows joinedRows = element.tableContents( - evaluator); - - ResultRows afterWhere = joinedRows.select(where, evaluator); - - ResultRows afterGrouping = groupBy.group(afterWhere, evaluator, selected); - - ResultRows afterDistinct = distinct(selected, afterGrouping); - - ResultRows sorted = orderBy.sort(afterDistinct, what, evaluator); - return limit.limit(sorted); - } - - private ResultRows distinct(Selected selected, ResultRows rows) { - if (!distinct) { + public static ResultRows distinct(Selected selected, ResultRows rows, boolean isDistinct) { + if (!isDistinct) { return rows; } @@ -131,7 +121,7 @@ return distinctRowsToResultRows(selected, distinctRows); } - private ResultRows distinctRowsToResultRows(Selected selected, Set distinctRows) { + private static ResultRows distinctRowsToResultRows(Selected selected, Set distinctRows) { ResultRows result = new ResultRows(); for (Iterator iter = distinctRows.iterator(); iter.hasNext();) { GroupByCells cells = (GroupByCells) iter.next(); @@ -140,7 +130,7 @@ return result; } - private Set constructDistinctRows(Selected selected, ResultRows rows) { + private static Set constructDistinctRows(Selected selected, ResultRows rows) { Set distinctRows = new LinkedHashSet(); for (Iterator iter = rows.iterator(); iter.hasNext();) { ResultRow row = (ResultRow) iter.next(); Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/InsertSubselectTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/InsertSubselectTest.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/InsertSubselectTest.java 2008-05-10 02:11:28 UTC (rev 560) @@ -25,48 +25,27 @@ execute("create table src(d integer, e integer, f integer)"); execute("create table dest(a integer, b integer, c integer)"); - String insert = "insert into dest(a, b) select d, e, f from src"; - if (dialect.wishThisWereTrue()) { - expectExecuteFailure(insert, - "Too many values.\n" + - "Columns and values were:\n" + - "a d\n" + - "b e\n" + - "(none) f\n"); - } - else { - execute(insert); - execute("insert into src(d, e, f) values(1, 2, 3)"); - expectExecuteFailure(insert, - "Too many values.\n" + - "Columns and values were:\n" + - "a 1\n" + - "b 2\n" + - "(none) 3\n"); - } + expectExecuteFailure( + "insert into dest(a, b) select d, e, f from src", + + "Too many values.\n" + + "Columns and values from subselect were:\n" + + "a d\n" + + "b e\n" + + "(none) f\n"); } public void testTooFewValues() throws Exception { execute("create table src(d integer, e integer, f integer)"); execute("create table dest(a integer, b integer, c integer)"); - String insert = "insert into dest(a, b) select d from src"; - if (dialect.wishThisWereTrue()) { - expectExecuteFailure(insert, - "Too few values.\n" + - "Columns and values were:\n" + - "a d\n" + - "b (none)\n"); - } - else { - execute(insert); - execute("insert into src(d, e, f) values(1, 2, 3)"); - expectExecuteFailure(insert, - "Too few values.\n" + - "Columns and values were:\n" + - "a 1\n" + - "b (none)\n"); - } + expectExecuteFailure( + "insert into dest(a, b) select d from src", + + "Too few values.\n" + + "Columns and values from subselect were:\n" + + "a d\n" + + "b (none)\n"); } public void testImplicitDestinationColumns() throws Exception { @@ -78,7 +57,19 @@ assertResultSet(new String[] { " 1, 2, 3 " }, query("select a, b, c from dest")); } + + public void testStillCheckCountWhenDestinationColumnsAreImplicit() throws Exception { + execute("create table src(d integer, e integer, f integer)"); + execute("create table dest(a integer, b integer, c integer)"); + expectExecuteFailure("insert into dest select d, e from src", + "Too few values.\n" + + "Columns and values from subselect were:\n" + + "a d\n" + + "b e\n" + + "c (none)\n"); + } + public void testImplicitSourceColumns() throws Exception { execute("create table src(d integer, e integer, f integer)"); execute("insert into src(d, e, f) values(1, 2, 3)"); Modified: trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/test/net/sourceforge/mayfly/datastore/DataStoreTest.java 2008-05-10 02:11:28 UTC (rev 560) @@ -3,6 +3,7 @@ import junit.framework.TestCase; import net.sourceforge.mayfly.evaluation.ValueList; +import net.sourceforge.mayfly.util.ImmutableList; import java.util.Collections; @@ -13,7 +14,7 @@ .addSchema("mars", new Schema().createTable("foo", Collections.singletonList("x"))); DataStore newStore = store.addRow( new TableReference("mars", "foo"), - Collections.singletonList("x"), ValueList.singleton(new LongCell(5)), + ImmutableList.singleton("x"), ValueList.singleton(new LongCell(5)), new NullChecker()); assertEquals(1, newStore.table("mars", "foo").rowCount()); } Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java 2008-05-04 05:01:13 UTC (rev 559) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/SelectTest.java 2008-05-10 02:11:28 UTC (rev 560) @@ -20,7 +20,6 @@ import net.sourceforge.mayfly.evaluation.expression.literal.IntegerLiteral; import net.sourceforge.mayfly.evaluation.from.FromTable; import net.sourceforge.mayfly.evaluation.from.InnerJoin; -import net.sourceforge.mayfly.evaluation.what.Selected; import net.sourceforge.mayfly.util.ImmutableList; import net.sourceforge.mayfly.util.L; import net.sourceforge.mayfly.util.MayflyAssert; @@ -28,8 +27,8 @@ public class SelectTest extends TestCase { public void testExecuteSimpleJoin() throws Exception { - L fooColumns = new L().append("colA").append("colB"); - L barColumns = new L().append("colX").append("colY"); + ImmutableList fooColumns = new L().append("colA").append("colB").asImmutable(); + ImmutableList barColumns = new L().append("colX").append("colY").asImmutable(); Evaluator evaluator = new StoreEvaluator( new Schema() @@ -81,8 +80,8 @@ private ResultRows query(Evaluator evaluator, String sql) { Select select = (Select) Command.fromSql(sql); - select.optimize(); - return select.query(evaluator, new Selected()); + OptimizedSelect optimized = select.makeOptimized(evaluator); + return optimized.query(); } public void testSmallerJoin() throws Exception { @@ -90,10 +89,10 @@ new StoreEvaluator( new Schema() .createTable("foo", new L().append("colA")) - .addRow("foo", new L().append("colA"), ValueList.singleton(new StringCell("1a"))) + .addRow("foo", new ImmutableList().with("colA"), ValueList.singleton(new StringCell("1a"))) .createTable("bar", new L().append("colX")) - .addRow("bar", new L().append("colX"), ValueList.singleton(new StringCell("barXValue"))) + .addRow("bar", new ImmutableList().with("colX"), ValueList.singleton(new StringCell("barXValue"))) ); @@ -102,7 +101,7 @@ } public void testSimpleWhere() throws Exception { - L columnNames = new L().append("colA").append("colB"); + ImmutableList columnNames = new ImmutableList().with("colA").with("colB"); Evaluator evaluator = new StoreEvaluator( new Schema() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-05-04 05:01:17
|
Revision: 559 http://mayfly.svn.sourceforge.net/mayfly/?rev=559&view=rev Author: kingdon Date: 2008-05-03 22:01:13 -0700 (Sat, 03 May 2008) Log Message: ----------- Fix a known bug with aggregates in HAVING. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/ResultRowTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/condition/ConditionTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/expression/SingleColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java 2008-05-04 05:01:13 UTC (rev 559) @@ -1,7 +1,6 @@ package net.sourceforge.mayfly.evaluation; import net.sourceforge.mayfly.MayflyException; -import net.sourceforge.mayfly.UnimplementedException; import net.sourceforge.mayfly.evaluation.condition.Condition; import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.evaluation.what.Selected; @@ -35,7 +34,7 @@ } public ResultRow check(ResultRow afterJoins, Evaluator evaluator, Selected selected) { -// having = having.resolve(afterJoins, evaluator); + having = having.resolve(afterJoins, evaluator); keys.resolve(afterJoins, evaluator); GroupedRows grouped = makeGroupedRows(new ResultRows(afterJoins), evaluator); @@ -52,11 +51,6 @@ having.evaluate(afterGroupBy, evaluator); } catch (NoColumn doesNotSurviveGroupBy) { - if (having.isAggregate()) { - throw new UnimplementedException( - "aggregates in HAVING not yet fully implemented"); - } - having.evaluate(afterJoins, evaluator); throw new MayflyException(doesNotSurviveGroupBy.displayName() + " is not aggregate or mentioned in GROUP BY", Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java 2008-05-04 05:01:13 UTC (rev 559) @@ -82,19 +82,17 @@ } public Expression findColumn(String columnName) { - return findColumn(null, columnName); + return findColumn(null, null, columnName, Location.UNKNOWN); } - public SingleColumn findColumn(String tableOrAlias, String columnName) { - return findColumn(tableOrAlias, columnName, Location.UNKNOWN); - } - - public SingleColumn findColumn(String tableOrAlias, String columnName, + public SingleColumn findColumn( + String tableOrAlias, String originalTableOrAlias, String columnName, Location location) { SingleColumn found = findColumnOrNull(tableOrAlias, columnName, location); if (found == null) { - throw new NoColumn(tableOrAlias, columnName, location); - } else { + throw new NoColumn(originalTableOrAlias, columnName, location); + } + else { return found; } } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java 2008-05-04 05:01:13 UTC (rev 559) @@ -12,8 +12,8 @@ import net.sourceforge.mayfly.parser.Location; public class SingleColumn extends Expression { - private final String originalTableOrAlias; private final String tableOrAlias; + public final String originalTableOrAlias; private final String columnName; public final Options options; @@ -49,17 +49,18 @@ @Override public Cell evaluate(ResultRow row, Evaluator evaluator) { - return evaluator.lookup(row, tableOrAlias, columnName, location); + return evaluator.lookup(row, tableOrAlias, originalTableOrAlias, columnName, location); } @Override public Cell evaluate(ResultRow row) { - Expression found = row.findColumn(tableOrAlias, columnName, location); + Expression found = lookup(row); return row.findValue(found); } public SingleColumn lookup(ResultRow row) { - return row.findColumn(tableOrAlias, columnName, location); + return row.findColumn( + tableOrAlias, originalTableOrAlias, columnName, location); } @Override Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java 2008-05-04 05:01:13 UTC (rev 559) @@ -35,9 +35,9 @@ } @Override - public Cell lookup(ResultRow row, String tableOrAlias, String columnName, Location location) { + public Cell lookup(ResultRow row, String tableOrAlias, String originalTableOrAlias, String columnName, Location location) { if (tableOrAlias != null) { - return delegate.lookup(row, tableOrAlias, columnName, location); + return delegate.lookup(row, tableOrAlias, originalTableOrAlias, columnName, location); } Expression aliasedTo = what.lookupAlias(columnName); @@ -45,7 +45,7 @@ return aliasedTo.evaluate(row); } else { - return delegate.lookup(row, tableOrAlias, columnName, location); + return delegate.lookup(row, tableOrAlias, originalTableOrAlias, columnName, location); } } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java 2008-05-04 05:01:13 UTC (rev 559) @@ -40,8 +40,9 @@ abstract public String currentSchema(); public Cell lookup(ResultRow row, - String tableOrAlias, String columnName, Location location) { - Expression found = row.findColumn(tableOrAlias, columnName, location); + String tableOrAlias, String originalTableOrAlias, String columnName, Location location) { + Expression found = row.findColumn( + tableOrAlias, originalTableOrAlias, columnName, location); return row.findValue(found); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-05-04 05:01:13 UTC (rev 559) @@ -32,12 +32,12 @@ @Override public Cell lookup(ResultRow row, - String tableOrAlias, String columnName, Location location) { + String tableOrAlias, String originalTableOrAlias, String columnName, Location location) { try { - return super.lookup(row, tableOrAlias, columnName, location); + return super.lookup(row, tableOrAlias, originalTableOrAlias, columnName, location); } catch (NoColumn e) { - return nestedEvaluator.lookup(this.row, tableOrAlias, columnName, location); + return nestedEvaluator.lookup(this.row, tableOrAlias, originalTableOrAlias, columnName, location); } } Modified: trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-05-04 05:01:13 UTC (rev 559) @@ -141,11 +141,12 @@ new ResultRow() { @Override public SingleColumn findColumn( - String tableOrAlias, String columnName, + String tableOrAlias, String originalTableOrAlias, + String columnName, Location location) { throw new MayflyException( "values clause may not refer to column: " - + Column.displayName(tableOrAlias, columnName), + + Column.displayName(originalTableOrAlias, columnName), location ); } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java 2008-05-04 05:01:13 UTC (rev 559) @@ -306,14 +306,7 @@ query("select avg(x) from foo group by y having avg(foo.x) < 5")); String sql = "select avg(x) from foo group by y having avg(x) < 5"; - if (dialect.wishThisWereTrue()) { - assertResultList(new String[] { " 2 " }, query(sql)); - } - else { - expectQueryFailure(sql, - "aggregates in HAVING not yet fully implemented"); - } - + assertResultList(new String[] { " 2 " }, query(sql)); } public void testHavingIsKeyExpression() throws Exception { Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/ResultRowTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/ResultRowTest.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/ResultRowTest.java 2008-05-04 05:01:13 UTC (rev 559) @@ -13,6 +13,7 @@ import net.sourceforge.mayfly.evaluation.expression.Plus; import net.sourceforge.mayfly.evaluation.expression.SingleColumn; import net.sourceforge.mayfly.evaluation.expression.literal.IntegerLiteral; +import net.sourceforge.mayfly.parser.Location; import net.sourceforge.mayfly.util.MayflyAssert; public class ResultRowTest extends TestCase { @@ -80,15 +81,23 @@ .withColumn("bar", "x", new LongCell(5)) .with(new CountAll("count"), new LongCell(15)) ; - SingleColumn column = row.findColumn("bar", "x"); + SingleColumn column = row.findColumn("bar", null, "x", Location.UNKNOWN); assertEquals("bar", column.tableOrAlias()); assertEquals("x", column.columnName()); try { - row.findColumn("bar", "y"); + row.findColumn("bar", null, "y", Location.UNKNOWN); fail(); } catch (NoColumn e) { + assertEquals("no column y", e.getMessage()); + } + + try { + row.findColumn("bar", "bar", "y", Location.UNKNOWN); + fail(); + } + catch (NoColumn e) { assertEquals("no column bar.y", e.getMessage()); } } Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/condition/ConditionTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/condition/ConditionTest.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/condition/ConditionTest.java 2008-05-04 05:01:13 UTC (rev 559) @@ -3,6 +3,7 @@ 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; @@ -13,6 +14,7 @@ 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; @@ -135,14 +137,32 @@ } 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()); - condition.check(row); + 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 { Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/expression/SingleColumnTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/expression/SingleColumnTest.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/expression/SingleColumnTest.java 2008-05-04 05:01:13 UTC (rev 559) @@ -5,6 +5,7 @@ import net.sourceforge.mayfly.Options; import net.sourceforge.mayfly.datastore.LongCell; import net.sourceforge.mayfly.evaluation.Expression; +import net.sourceforge.mayfly.evaluation.NoColumn; import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.expression.literal.IntegerLiteral; import net.sourceforge.mayfly.evaluation.select.AliasEvaluator; @@ -55,11 +56,27 @@ "x", new Location(5, 20, 7, 24), new Options()); SingleColumn resolved = (SingleColumn) unresolved.resolve(row); + assertEquals(null, resolved.originalTableOrAlias); + assertEquals("x", resolved.displayName()); assertEquals("foo", resolved.tableOrAlias()); assertEquals("x", resolved.columnName()); assertEquals(20, resolved.location.startColumn); } + public void testEvaluatePassesOriginalTableToException() throws Exception { + SingleColumn unresolved = (SingleColumn) + new Parser("x").parseExpression().asNonBoolean(); + SingleColumn resolved = (SingleColumn) unresolved.resolve( + new ResultRow().withColumn("foo", "x", new LongCell(7))); + try { + resolved.evaluate(new ResultRow()); + fail(); + } + catch (NoColumn expected) { + assertEquals("no column x", expected.getMessage()); + } + } + public void testResolveWithColumnAlias() throws Exception { ResultRow row = new ResultRow().withColumn("foo", "x", new LongCell(7)); SingleColumn unresolved = new SingleColumn( Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java 2008-05-04 05:01:13 UTC (rev 559) @@ -69,7 +69,7 @@ private void check(long expected, String table, String column, Evaluator evaluator, ResultRow row) { - LongCell value = (LongCell) evaluator.lookup(row, table, column, null); + LongCell value = (LongCell) evaluator.lookup(row, table, table, column, null); assertEquals(expected, value.asLong()); } Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-05-02 04:32:13 UTC (rev 558) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-05-04 05:01:13 UTC (rev 559) @@ -21,10 +21,10 @@ RowEvaluator evaluator = new RowEvaluator(correlatedRow, nested); ResultRow rowFromInner = new ResultRow().withColumn("bbb", "b", new LongCell(8)); - assertLong(7, evaluator.lookup(rowFromInner, "aaa", "a", Location.UNKNOWN)); - assertLong(7, evaluator.lookup(rowFromInner, null, "a", Location.UNKNOWN)); - assertLong(8, evaluator.lookup(rowFromInner, "bbb", "b", Location.UNKNOWN)); - assertLong(8, evaluator.lookup(rowFromInner, null, "b", Location.UNKNOWN)); + assertLong(7, evaluator.lookup(rowFromInner, "aaa", null, "a", Location.UNKNOWN)); + assertLong(7, evaluator.lookup(rowFromInner, null, null, "a", Location.UNKNOWN)); + assertLong(8, evaluator.lookup(rowFromInner, "bbb", null, "b", Location.UNKNOWN)); + assertLong(8, evaluator.lookup(rowFromInner, null, null, "b", Location.UNKNOWN)); checkLookupFails(rowFromInner, evaluator, null, "c", "c"); checkLookupFails(rowFromInner, evaluator, "ccc", "c", "ccc.c"); checkLookupFails(rowFromInner, evaluator, "aaa", "b", "aaa.b"); @@ -35,7 +35,7 @@ ResultRow row, RowEvaluator evaluator, String table, String column, String expectedDisplayName) { try { - evaluator.lookup(row, table, column, Location.UNKNOWN); + evaluator.lookup(row, table, table, column, Location.UNKNOWN); fail(); } catch (NoColumn expected) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-05-02 04:32:17
|
Revision: 558 http://mayfly.svn.sourceforge.net/mayfly/?rev=558&view=rev Author: kingdon Date: 2008-05-01 21:32:13 -0700 (Thu, 01 May 2008) Log Message: ----------- Fix a testsuite expectation to reflect the behavior of H2. I'm not sure whether I missed this before, or whether it has something to do with my upgrade to Fedora 8. Modified Paths: -------------- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java 2008-05-01 04:46:45 UTC (rev 557) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java 2008-05-02 04:32:13 UTC (rev 558) @@ -181,7 +181,8 @@ } public boolean callJavaMethodAsStoredProcedure() { - // Not even H2 supports this syntax. So maybe there is a better way. + /* Not even H2 supports this syntax. So maybe CREATE ALIAS is + considered to be a better way. */ return true; } @@ -193,7 +194,7 @@ return true; } - public boolean complainAboutStoredProcedureOverloadingOnArgumentType() { + public boolean complainAboutStoredProcedureOverloadingOnArgumentTypeOrCount() { return true; } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java 2008-05-01 04:46:45 UTC (rev 557) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java 2008-05-02 04:32:13 UTC (rev 558) @@ -73,7 +73,7 @@ } @Override - public boolean complainAboutStoredProcedureOverloadingOnArgumentType() { + public boolean complainAboutStoredProcedureOverloadingOnArgumentTypeOrCount() { return false; } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java 2008-05-01 04:46:45 UTC (rev 557) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java 2008-05-02 04:32:13 UTC (rev 558) @@ -355,7 +355,7 @@ } @Override - public boolean complainAboutStoredProcedureOverloadingOnArgumentType() { + public boolean complainAboutStoredProcedureOverloadingOnArgumentTypeOrCount() { return false; } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java 2008-05-01 04:46:45 UTC (rev 557) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java 2008-05-02 04:32:13 UTC (rev 558) @@ -54,7 +54,7 @@ execute("insert into foo(a) values(5)"); createAlias("overloaded"); String query = "select overloaded(a) from foo"; - if (dialect.complainAboutDubiousStoredProcedure()) { + if (dialect.complainAboutStoredProcedureOverloadingOnArgumentTypeOrCount()) { expectQueryFailure(query, "multiple methods found for stored procedure.\n" + "class: " + getClass().getName() + "\n" + @@ -85,7 +85,7 @@ execute("insert into foo(a) values(5)"); createAlias("onType"); String query = "select onType(a) from foo"; - if (dialect.complainAboutStoredProcedureOverloadingOnArgumentType()) { + if (dialect.complainAboutStoredProcedureOverloadingOnArgumentTypeOrCount()) { expectQueryFailure(query, "multiple methods found for stored procedure.\n" + "class: " + getClass().getName() + "\n" + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-05-01 04:46:49
|
Revision: 557 http://mayfly.svn.sourceforge.net/mayfly/?rev=557&view=rev Author: kingdon Date: 2008-04-30 21:46:45 -0700 (Wed, 30 Apr 2008) Log Message: ----------- Add a test for some cases with NOT and LIKE (and implement string NOT LIKE pattern). Move a bunch of tests from acceptance into sub-packages thereof. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java trunk/mayfly/test/net/sourceforge/mayfly/EndToEndTests.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/InsertSubselectTest.java trunk/mayfly/test/net/sourceforge/mayfly/parser/ParserTest.java Added Paths: ----------- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/AddColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/AddForeignKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/AddUniqueTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DataDefinitionTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropForeignKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/DropUniqueConstraintTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/ModifyColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/definition/RenameColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/DataTypeTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/DateTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/ExpressionTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/StringTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/SubselectTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/ValueTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/expression/WhereTest.java Removed Paths: ------------- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddForeignKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataDefinitionTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DateTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropForeignKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropUniqueConstraintTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ExpressionTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ModifyColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/RenameColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StringTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/SubselectTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ValueTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/WhereTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-05-01 04:46:45 UTC (rev 557) @@ -5,6 +5,7 @@ import static net.sourceforge.mayfly.parser.TokenType.IDENTIFIER; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_character; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_column; +import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_like; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_on; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_set; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_values; @@ -1193,9 +1194,8 @@ Expression right = parsePrimary().asNonBoolean(); return new BooleanParserExpression(new Equal(left.asNonBoolean(), right)); } - if (consumeIfMatches(TokenType.KEYWORD_like)) { - Expression right = parsePrimary().asNonBoolean(); - return new BooleanParserExpression(new Like(left.asNonBoolean(), right)); + if (currentToken.type == TokenType.KEYWORD_like) { + return new BooleanParserExpression(parseLike(left)); } else if (consumeIfMatches(TokenType.LESS_GREATER)) { Expression right = parsePrimary().asNonBoolean(); @@ -1224,7 +1224,7 @@ new LessEqual(right, left.asNonBoolean())); } else if (consumeIfMatches(TokenType.KEYWORD_not)) { - return new BooleanParserExpression(new Not(parseIn(left.asNonBoolean()))); + return parseNotOperator(left); } else if (currentToken.type == TokenType.KEYWORD_in) { return new BooleanParserExpression(parseIn(left.asNonBoolean())); @@ -1240,6 +1240,27 @@ } } + private Like parseLike(ParserExpression left) { + expectAndConsume(KEYWORD_like); + Expression right = parsePrimary().asNonBoolean(); + return new Like(left.asNonBoolean(), right); + } + + /* + * x NOT IN y, x NOT LIKE y, etc. + */ + private BooleanParserExpression parseNotOperator(ParserExpression left) { + if (currentToken.type == TokenType.KEYWORD_in) { + return new BooleanParserExpression(new Not(parseIn(left.asNonBoolean()))); + } + else if (currentToken.type == KEYWORD_like) { + return new BooleanParserExpression(new Not(parseLike(left))); + } + else { + throw new ParserException("IN or LIKE", currentToken); + } + } + private Condition parseIs(Expression left) { expectAndConsume(TokenType.KEYWORD_null); return new IsNull(left); Modified: trunk/mayfly/test/net/sourceforge/mayfly/EndToEndTests.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/EndToEndTests.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/EndToEndTests.java 2008-05-01 04:46:45 UTC (rev 557) @@ -60,7 +60,7 @@ /** * @internal - * In {@link net.sourceforge.mayfly.acceptance.StringTest#testCharacterStream()} we test + * In {@link net.sourceforge.mayfly.acceptance.expression.StringTest#testCharacterStream()} we test * setting parameters with a length, and results via * an index. So here we test setting parameters without * a length (which should work, as described there), Deleted: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddColumnTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddColumnTest.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddColumnTest.java 2008-05-01 04:46:45 UTC (rev 557) @@ -1,109 +0,0 @@ -package net.sourceforge.mayfly.acceptance; - -public class AddColumnTest extends SqlTestCase { - - public void testBasics() throws Exception { - execute("create table foo(a integer)"); - assertEquals(0, execute("alter table foo add column b integer")); - execute("insert into foo(b, a) values(7,5)"); - assertResultSet(new String[] { " 5, 7 " }, query("select a, b from foo")); - } - - public void testColumnAlreadyExists() throws Exception { - execute("create table foo(a integer)"); - expectExecuteFailure("alter table foo add column a integer", - "column a already exists"); - } - - public void testExistingRow() throws Exception { - execute("create table foo(a integer)"); - execute("insert into foo(a) values(5)"); - execute("insert into foo(a) values(6)"); - - assertEquals( - dialect.addingColumnCountsAsAffectedRow() ? 2 : 0, - execute("alter table foo add column b integer")); - - assertResultSet(new String[] { " 5, null ", " 6, null " }, - query("select a, b from foo")); - } - - public void testNotNull() throws Exception { - execute("create table foo(a integer)"); - execute("insert into foo(a) values(5)"); - - String noDefault = "alter table foo add column b integer not null"; - if (dialect.notNullImpliesDefaults()) { - execute(noDefault); - assertResultSet(new String[] { " 5, 0 " }, query("select a, b from foo")); - } - else { - expectExecuteFailure(noDefault, - // "violation of not null constraint" or something might also be OK - "no default value for column b"); - execute("alter table foo add column b integer default 7 not null"); - assertResultSet(new String[] { " 5, 7 " }, query("select a, b from foo")); - } - } - - public void testNotNullButNoRows() throws Exception { - execute("create table foo(a integer)"); - String noDefault = "alter table foo add column b integer not null"; - if (dialect.notNullRequiresDefault()) { - expectExecuteFailure(noDefault, "no default value for column b"); - } - else { - execute(noDefault); - execute("insert into foo(a, b) values (5, 7)"); - } - } - - public void testLast() throws Exception { - execute("create table foo(a integer, b integer)"); - execute("insert into foo values(1, 10)"); - execute("alter table foo add column c integer"); - execute("insert into foo values(2, 20, 200)"); - assertResultSet(new String[] { - "1, 10, null", - "2, 20, 200" - }, - query("select a, b, c from foo")); - } - - public void testAfter() throws Exception { - execute("create table foo(a integer, c integer)"); - execute("insert into foo values(1, 100)"); - String sql = "alter table foo add column b integer after a"; - if (dialect.haveAddColumnAfter()) { - execute(sql); - execute("insert into foo values(2, 20, 200)"); - assertResultSet(new String[] { - "1, null, 100", - "2, 20, 200" - }, - query("select a, b, c from foo")); - } - else { - expectExecuteFailure(sql, "expected end of file but got after"); - } - } - - public void testFirst() throws Exception { - execute("create table foo(b integer, c integer)"); - execute("insert into foo values(10, 100)"); - String sql = "alter table foo add column a integer first"; - if (dialect.haveAddColumnAfter()) { - execute(sql); - execute("insert into foo values(2, 20, 200)"); - assertResultSet(new String[] { - "null, 10, 100", - "2, 20, 200" - }, - query("select a, b, c from foo")); - } - else { - expectExecuteFailure(sql, "expected end of file but got after"); - } - } - -} Deleted: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddForeignKeyTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddForeignKeyTest.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddForeignKeyTest.java 2008-05-01 04:46:45 UTC (rev 557) @@ -1,68 +0,0 @@ -package net.sourceforge.mayfly.acceptance; - -public class AddForeignKeyTest extends SqlTestCase { - - public void testBasics() throws Exception { - execute("create table foo(id integer primary key)" + - dialect.tableTypeForForeignKeys()); - execute("create table bar(foo_id integer)" + - dialect.tableTypeForForeignKeys()); - execute("insert into bar values(5)"); - execute("insert into bar values(6)"); - execute("insert into foo values(5)"); - - String add = "alter table bar add foreign key (foo_id) references foo(id)"; - expectExecuteFailure(add, - dialect.wishThisWereTrue() ? - "attempt to add foreign key from table bar, column foo_id " + - "where existing value 6 references non-present value " + - "in table foo, column id, " : - - "foreign key violation: attempt in table bar, column foo_id " + - "to reference non-present value 6 in table foo, column id"); - - execute("delete from bar where foo_id = 6"); - execute(add); - - expectExecuteFailure("insert into bar values(6)", - "foreign key violation: attempt in table bar, column foo_id " + - "to reference non-present value 6 in table foo, column id"); - } - - public void testConstraintNames() throws Exception { - execute("create table foo(id integer primary key)" + - dialect.tableTypeForForeignKeys()); - execute("create table bar(first_foo integer, second_foo integer)" + - dialect.tableTypeForForeignKeys()); - - execute("alter table bar add constraint bar_foo " + - "foreign key (first_foo) references foo(id)"); - expectExecuteFailure("alter table bar add constraint bar_foo " + - "foreign key (second_foo) references foo(id)", - "duplicate constraint name bar_foo"); - execute("alter table bar add constraint bar_second_foo " + - "foreign key (second_foo) references foo(id)"); - } - - public void testRemoveCreatesGap() throws Exception { - if (!dialect.haveDropForeignKey() || !dialect.nameForeignKeysWithIbfk()) { - return; - } - - execute("create table foo(id integer primary key)" + - dialect.tableTypeForForeignKeys()); - execute("create table bar(f1 integer, f2 integer, f3 integer)" + - dialect.tableTypeForForeignKeys()); - - execute("alter table bar add foreign key(f1) references foo(id)"); - execute("alter table bar add foreign key(f2) references foo(id)"); - execute("alter table bar drop foreign key bar_ibfk_1"); - execute("alter table bar add foreign key(f3) references foo(id)"); - execute("alter table bar drop foreign key bar_ibfk_2"); - execute("alter table bar drop foreign key bar_ibfk_3"); - - // verify all foreign keys are gone - execute("insert into bar(f1, f2, f3) values(4, 5, 6)"); - } - -} Deleted: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java 2008-05-01 04:46:45 UTC (rev 557) @@ -1,111 +0,0 @@ -package net.sourceforge.mayfly.acceptance; - -import java.sql.SQLException; - -public class AddUniqueTest extends SqlTestCase { - - public void testBasics() throws Exception { - execute("create table foo(id integer" + - (dialect.uniqueColumnMayBeNullable() ? "" : " not null") + - ", x integer)"); - execute("insert into foo values(3, 10)"); - execute("insert into foo values(5, 10)"); - execute("insert into foo values(5, 20)"); - if (dialect.uniqueColumnMayBeNullable()) { - execute("insert into foo values(null, 40)"); - } - - String add = "alter table foo add unique(id)"; - /* Perhaps "unique column id has duplicate value 5" would be - nicer wording in that we aren't adding a 5 and conflicting - with one there; there are two there. But is this really - confusing or only inaccurate in a nit-picky way? - */ - expectExecuteFailure(add, "unique constraint in table foo, column id: duplicate value 5"); - - execute("delete from foo where x = 20"); - execute(add); - - expectExecuteFailure("insert into foo values(5, 30)", - "unique constraint in table foo, column id: duplicate value 5"); - - if (dialect.uniqueColumnMayBeNullable()) { - String secondNull = "insert into foo values(null, 50)"; - if (dialect.allowMultipleNullsInUniqueColumn()) { - execute(secondNull); - } - else { - expectExecuteFailure(secondNull, - "unique constraint in table foo, column id: duplicate value null"); - } - } - } - - public void testConstraintNames() throws Exception { - execute("create table foo(id integer not null, x integer not null)"); - - execute("alter table foo add constraint foo_unique unique(id)"); - expectExecuteFailure( - "alter table foo add constraint foo_unique unique(x)", - "duplicate constraint name foo_unique"); - String addPrimaryKey = "alter table foo add constraint foo_unique primary key(x)"; - if (dialect.duplicateConstraintNamesOk()) { - execute(addPrimaryKey); - } - else { - expectExecuteFailure( - addPrimaryKey, - "duplicate constraint name foo_unique"); - execute("alter table foo add constraint foo_x unique(x)"); - } - } - - public void testPrimaryKey() throws Exception { - execute("create table foo(id integer, x integer)"); - execute("insert into foo values(3, 10)"); - execute("insert into foo values(5, 10)"); - execute("insert into foo values(5, 20)"); - - String add = "alter table foo add primary key(id)"; - expectExecuteFailure(add, "primary key in table foo, column id: duplicate value 5"); - - execute("update foo set id = null where x = 20"); - if (dialect.notNullImpliesDefaults()) { - try { - execute(add); - failForMissingException(add, - "Data truncated for column 'id' at row 3"); - } catch (SQLException expected) { - assertEquals("Data truncation: Data truncated for column 'id' at row 3", - expected.getMessage()); - } - expectExecuteFailure("insert into foo values(5, 30)", - "primary key in table foo, column id: duplicate value 5"); - } - else { - expectExecuteFailure(add, "primary key id cannot be null"); - - execute("update foo set id = 7 where x = 20"); - if (dialect.canTurnNullableColumnIntoPrimaryKey()) { - execute(add); - - expectExecuteFailure("insert into foo values(5, 30)", - "primary key in table foo, column id: duplicate value 5"); - } - else { - /* I'm not sure there is a way out other than copying - the table. Derby doesn't have MODIFY COLUMN to add - the NOT NULL with... */ - expectExecuteFailure(add, "missing NOT NULL"); - } - } - } - - public void testTwoPrimaryKeys() throws Exception { - execute("create table foo(id integer primary key, x integer not null)"); - - expectExecuteFailure("alter table foo add primary key(x)", - "attempt to define more than one primary key for table foo"); - } - -} Deleted: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataDefinitionTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataDefinitionTest.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataDefinitionTest.java 2008-05-01 04:46:45 UTC (rev 557) @@ -1,68 +0,0 @@ -package net.sourceforge.mayfly.acceptance; - -/** - * Tests of creating and dropping tables. - * Also see {@link net.sourceforge.mayfly.acceptance.AddColumnTest} - * and {@link net.sourceforge.mayfly.acceptance.DropColumnTest}. - */ -public class DataDefinitionTest extends SqlTestCase { - - public void testDuplicateColumnName() throws Exception { - expectExecuteFailure("create table foo (Id integer, Id integer)", - "duplicate column Id"); - } - - public void testTableAlreadyExists() throws Exception { - execute("create table foo (x integer)"); - expectExecuteFailure("create table foo (y integer)", "table foo already exists"); - if (!dialect.tableNamesMightBeCaseSensitive()) { - expectExecuteFailure("create table FOO (y integer)", "table foo already exists"); - } - } - - // In our book, "data definition" includes "data undefinition". - // So that's what DROP TABLE tests are doing here. - - // Maybe there's a motto here: - // Mayfly, the most powerful data undefinition language around, - // featuring not just DROP but also the ability to let your Database - // be garbage collected or call JdbcDriver.shutdown(). - - /** - * @internal - * Also see {@link ForeignKeyTest#testDropTable()} and - * {@link ForeignKeyTest#testDropTableWithSchemas()}. - */ - - public void testDropNonexisting() throws Exception { - expectExecuteFailure("DROP TABLE FOO", "no table FOO"); - } - - public void testDropNonexistingIfExists() throws Exception { - if (dialect.haveDropTableFooIfExists()) { - execute("DROP TABLE foo IF EXISTS"); - } - } - - public void testDropIfExistsNonexisting() throws Exception { - if (dialect.haveDropTableIfExistsFoo()) { - execute("DROP TABLE IF EXISTS foo"); - } - } - - public void testDropExistingIfExists() throws Exception { - if (dialect.haveDropTableFooIfExists()) { - execute("create table foo (x integer)"); - execute("DROP TABLE foo IF EXISTS"); - // Now check that it is gone: - execute("create table foo (x integer)"); - } - } - - public void testDroppingTableDropsIndexes() throws Exception { - execute("create table foo(x integer not null)"); - execute("create index x_index on foo(x)"); - execute("drop table foo"); - } - -} Deleted: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java 2008-05-01 04:46:45 UTC (rev 557) @@ -1,815 +0,0 @@ -package net.sourceforge.mayfly.acceptance; - -import junitx.framework.ArrayAssert; -import junitx.framework.ObjectAssert; - -import org.apache.commons.io.IOUtils; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.math.BigDecimal; -import java.sql.Blob; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * @internal - * See also: - * {@link StringTest} - * {@link DateTest} - */ -public class DataTypeTest extends SqlTestCase { - - public void testTextType() throws Exception { - checkType(dialect.haveTextType(), "text", "'some text'"); - } - - public void testTinyint() throws Exception { - checkType(dialect.haveTinyint(), "tinyint", "127"); - } - - public void testSmallint() throws Exception { - checkType(true, "smallint", "32767"); - } - - public void testInt() throws Exception { - // A synonym for INTEGER. Specified by SQL92. - checkType(true, "Int", "2147483647"); - } - - // Here's a small sample of other types we don't test for yet: - //NUMERIC - //REAL, FLOAT, DOUBLE - precision can be given in binary digits (24 or 53, typically) - // BIT and BIT VARYING; BOOLEAN - // BIGSERIAL (see AutoIncrementTest for the auto-increment syntaxes we do look for) - // BLOB/CLOB - // sorting and comparison (binary for BLOB, Unicode-based or some such for CLOB) - // JDBC CLOB for a TEXT column - - /* Here are some we don't test for (or have in Mayfly), but which - I'm not sure are actually used enough to warrant the clutter: - CHARACTER VARYING (synonym for VARCHAR) - CHARACTER (non-VARYING) - this one seems to be the source of many - implementation headaches (trailing spaces and such), and I'm - not sure there is any good reason to prefer it over VARCHAR. - */ - - public void testInteger() throws Exception { - execute("create table foo (waist integer, inseam integer)"); - execute("insert into foo (waist, inseam) values (30, 32)"); - - { - ResultSet results = query("select waist, inseam from foo"); - assertTrue(results.next()); - assertEquals(30, results.getInt(1)); - assertEquals(32, results.getInt("inseam")); - assertFalse(results.next()); - results.close(); - } - - { - ResultSet results = query("select waist, inseam from foo"); - assertTrue(results.next()); - // Are these supposed to be Integer? Long? Hypersonic says Integer - assertEquals(30, ((Number) results.getObject(1)).intValue()); - assertEquals(32, ((Number) results.getObject("inseam")).intValue()); - assertFalse(results.next()); - results.close(); - } - } - - public void testGetObject() throws Exception { - execute("create table foo(x " + - (dialect.haveTinyint() ? "tinyint" : "smallint") + - ", y smallint, z integer, w bigint)"); - execute("insert into foo(x, y, z, w) " + - "values (127, 32767, -2147483648, 222111333444)"); - execute("insert into foo(x, y, z, w) " + - "values (0, 70, 5, 62)"); - ResultSet results = query("select x,y,z,w,y+z,z+w from foo"); - assertTrue(results.next()); - assertTypesOfRow(results); - assertTrue(results.next()); - assertTypesOfRow(results); - assertFalse(results.next()); - } - - private void assertTypesOfRow(ResultSet results) throws SQLException { - ObjectAssert.assertInstanceOf( - dialect.typeOfTinyint(), results.getObject("x")); - ObjectAssert.assertInstanceOf( - dialect.typeOfSmallint(), results.getObject("y")); - ObjectAssert.assertInstanceOf( - dialect.typeOfInteger(), results.getObject("z")); - ObjectAssert.assertInstanceOf(Long.class, results.getObject("w")); - ObjectAssert.assertInstanceOf( - dialect.expressionsAreTypeLong() ? Long.class : Integer.class, - results.getObject(5)); - ObjectAssert.assertInstanceOf( - dialect.typeFromAddingLongs(), results.getObject(6)); - } - - public void testLongDoesNotFit() throws Exception { - execute("create table foo (x bigint)"); - // larger than 2^32 - execute("insert into foo(x) values (222111333444)"); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - - assertEquals(222111333444L, results.getLong(1)); - - try { - results.getInt(1); - fail(); - } - catch (SQLException e) { - assertMessage("Value 222111333444 does not fit in an int", e); - } - - try { - results.getShort(1); - fail(); - } - catch (SQLException e) { - assertMessage("Value 222111333444 does not fit in a short", e); - } - - try { - results.getByte(1); - fail(); - } - catch (SQLException e) { - assertMessage("Value 222111333444 does not fit in a byte", e); - } - - assertFalse(results.next()); - results.close(); - } - - public void testLongWouldFit() throws Exception { - execute("create table foo (x bigint)"); - execute("insert into foo(x) values (42)"); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - - assertEquals(42L, results.getLong(1)); - assertEquals(42, results.getInt(1)); - assertEquals((short)42, results.getShort(1)); - assertEquals((byte)42, results.getByte(1)); - - assertFalse(results.next()); - results.close(); - } - - public void testSetShort() throws Exception { - execute("create table foo(x bigint)"); - PreparedStatement insert = - connection.prepareStatement("insert into foo(x) values(?)"); - insert.setByte(1, Byte.MIN_VALUE); - insert.executeUpdate(); - - insert.setShort(1, Short.MIN_VALUE); - insert.executeUpdate(); - - insert.setInt(1, Integer.MIN_VALUE); - insert.executeUpdate(); - - insert.setLong(1, Long.MIN_VALUE); - insert.executeUpdate(); - - assertResultSet( - new String[] { " -128 ", " -32768", - " -2147483648 ", " -9223372036854775808 " }, - query("select x from foo")); - } - - private void checkType(boolean expectType, String typeName, String sampleValue) - throws SQLException { - String sql = "create table foo (a " + typeName + ")"; - if (expectType) { - execute(sql); - execute("insert into foo(a) values(" + sampleValue + ")"); - assertResultSet(new String[] { sampleValue }, query("select a from foo")); - } - else { - expectExecuteFailure(sql, "expected data type but got " + typeName); - } - } - - public void testHexInteger() throws Exception { - execute("create table foo(a integer)"); - String hexForInteger = "insert into foo(a) values(x'a0')"; - if (dialect.allowHexForInteger()) { - execute(hexForInteger); - execute("insert into foo(a) values(x'ff')"); - execute("insert into foo(a) values(x'3fff0000')"); - - expectExecuteFailure("insert into foo(a) values(x'7')", - "hex constant 7 must have an even number of digits"); - expectExecuteFailure("insert into foo(a) values(x'7ff')", - "hex constant 7ff must have an even number of digits"); - expectExecuteFailure("insert into foo(a) values(x'0g')", - "invalid character g in hex constant 0g"); - - assertResultSet(new String[] { "160", "255", "1073676288" }, - query("select a from foo")); - } - else { - expectExecuteFailure(hexForInteger, - "attempt to store binary data into integer column a"); - } - } - - public void testDecimal() throws Exception { - execute("create table foo (price decimal(4, 2), list_price decimal(5, 2))"); - execute("insert into foo (price, list_price) values (95.0, 99.95)"); - - { - ResultSet results = query("select price, list_price from foo"); - assertTrue(results.next()); - - checkDecimal(9500, dialect.decimalScaleIsFromType() ? 2 : 1, - results.getBigDecimal(1)); - checkDecimal(9995, 2, results.getBigDecimal("list_price")); - - assertFalse(results.next()); - - results.close(); - } - - /* results.getBigDecimal with a scale intentionally not tested - as it is deprecated */ - - { - ResultSet results = query("select price, list_price from foo"); - assertTrue(results.next()); - - checkDecimal(9500, dialect.decimalScaleIsFromType() ? 2 : 1, - (BigDecimal) results.getObject(1)); - checkDecimal(9995, 2, (BigDecimal) results.getObject("list_price")); - - assertFalse(results.next()); - results.close(); - } - } - - private void checkDecimal(int expectedCents, int expectedScale, - BigDecimal actual) { - assertEquals(expectedCents, actual.movePointRight(2).intValue()); - assertEquals(expectedScale, actual.scale()); - } - - public void testIntegerToFromDecimalColumn() throws Exception { - execute("create table foo(price decimal(4,2))"); - execute("insert into foo(price) values(5)"); - PreparedStatement statement = connection.prepareStatement( - "insert into foo(price) values(?)"); - statement.setInt(1, 77); - statement.executeUpdate(); - - ResultSet results = query("select price from foo order by price"); - - assertTrue(results.next()); - assertEquals(5, results.getInt(1)); - checkDecimal(500, dialect.decimalScaleIsFromType() ? 2 : 0, - results.getBigDecimal(1)); - - assertTrue(results.next()); - assertEquals(77, results.getInt(1)); - assertFalse(results.next()); - } - - public void testSetDecimal() throws Exception { - execute("create table foo (price decimal(4, 2), y decimal(11,3))"); - PreparedStatement statement = connection.prepareStatement( - "insert into foo(price, y) values(?, ?)"); - statement.setBigDecimal(1, new BigDecimal("5.95")); - statement.setBigDecimal(2, new BigDecimal("197.952").negate()); - statement.executeUpdate(); - - ResultSet results = query("select price, y from foo"); - assertTrue(results.next()); - assertEquals(5.95, results.getDouble(1), 0.000001); - assertEquals(-197.952, results.getDouble(2), 0.000001); - assertFalse(results.next()); - } - - public void testSetDouble() throws Exception { - execute("create table foo (factor decimal(4, 2))"); - PreparedStatement statement = connection.prepareStatement( - "insert into foo(factor) values(?)"); - statement.setDouble(1, 3.14); - statement.executeUpdate(); - statement.setDouble(1, -0.03); - statement.executeUpdate(); - - ResultSet results = query("select factor from foo"); - assertTrue(results.next()); - assertEquals(314, - results.getBigDecimal(1).movePointRight(2).intValue()); - assertTrue(results.next()); - assertEquals(-3, - results.getBigDecimal(1).movePointRight(2).intValue()); - assertFalse(results.next()); - } - - public void testNullInDecimalColumn() throws Exception { - execute("create table foo(x decimal(7, 1))"); - execute("insert into foo(x) values(null)"); - assertResultSet(new String[] { " null " }, - query("select x from foo")); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - BigDecimal decimal = results.getBigDecimal("x"); - assertNull(decimal); - assertTrue(results.wasNull()); - assertFalse(results.next()); - results.close(); - } - - public void testStringColumnAsNumber() throws Exception { - execute("create table foo(x varchar(50))"); - execute("insert into foo(x) values('not decimal')"); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - try { - results.getByte("x"); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to read string 'not decimal' as a byte", e); - } - - try { - results.getShort("x"); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to read string 'not decimal' as a short", e); - } - - try { - results.getInt("x"); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to read string 'not decimal' as an int", e); - } - - try { - results.getLong("x"); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to read string 'not decimal' as a long", e); - } - - try { - results.getDouble("x"); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to read string 'not decimal' as a double", e); - } - - try { - results.getBigDecimal("x"); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to read string 'not decimal' as a decimal", e); - } - assertFalse(results.next()); - } - - public void testCompareStringWithInteger() throws Exception { - execute("create table foo(x integer, y varchar(255))"); - execute("insert into foo(x, y) values (5, 'hello')"); - - String integerColumnStringLiteral = "select y from foo where x < 'zzz'"; - if (dialect.dataTypesAreEnforced()) { - expectQueryFailure(integerColumnStringLiteral, - "attempt to compare string 'zzz' to number 5"); - } - else { - /* The obvious question here is what kind of comparison is - done - string or literal. But we don't test that. */ - query(integerColumnStringLiteral); - } - - String stringColumnIntegerLiteral = "select y from foo where y < 99"; - if (dialect.canMixStringAndInteger()) { - /* The obvious question here is what kind of comparison is - done - string or literal. But we don't test that. */ - query(stringColumnIntegerLiteral); - } - else { - expectQueryFailure(stringColumnIntegerLiteral, - "attempt to compare number 99 to string 'hello'"); - } - } - - public void testIntegerToFromStringColumn() throws Exception { - execute("create table foo(x varchar(255))"); - - String insertInteger = "insert into foo(x) values(9)"; - if (dialect.canMixStringAndInteger()) { - execute(insertInteger); - } - else { - expectExecuteFailure(insertInteger, - "attempt to store number 9 into string column x"); - execute("insert into foo(x) values('9')"); - } - - PreparedStatement statement = connection.prepareStatement( - "insert into foo(x) values(?)"); - statement.setInt(1, 10); - if (dialect.canSetIntegerOnStringColumn()) { - statement.executeUpdate(); - } - else { - try { - statement.executeUpdate(); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to store number 10 into string column x", e); - } - execute("insert into foo(x) values('10')"); - } - - ResultSet results = query("select x from foo order by x"); - - assertTrue(results.next()); - if (dialect.expectMayflyBehavior()) { - try { - results.getInt(1); - fail(); - } - catch (SQLException e) { - assertMessage("attempt to read string '10' as an int", e); - } - assertEquals("10", results.getString(1)); - assertTrue(results.next()); - assertEquals("9", results.getString(1)); - assertFalse(results.next()); - } - else { - assertEquals(10, results.getInt(1)); - assertTrue(results.next()); - assertEquals(9, results.getInt(1)); - assertFalse(results.next()); - } - - } - - public void testDecimalToFromStringColumn() throws Exception { - execute("create table foo(x varchar(255))"); - - String insertDecimal = "insert into foo(x) values(9.5)"; - if (dialect.canMixStringAndInteger()) { - execute(insertDecimal); - } - else { - expectExecuteFailure(insertDecimal, - "attempt to store decimal 9.5 into string column x"); - execute("insert into foo(x) values('9.5')"); - } - - PreparedStatement statement = connection.prepareStatement( - "insert into foo(x) values(?)"); - statement.setBigDecimal(1, new BigDecimal("10.05")); - if (dialect.canSetIntegerOnStringColumn()) { - statement.executeUpdate(); - } - else { - try { - statement.executeUpdate(); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to store decimal 10.05 into string column x", e); - } - execute("insert into foo(x) values('10.05')"); - } - - ResultSet results = query("select x from foo order by x"); - - assertTrue(results.next()); - if (dialect.expectMayflyBehavior()) { - try { - results.getBigDecimal(1); - fail(); - } - catch (SQLException e) { - assertMessage("attempt to read string '10.05' as a decimal", e); - } - assertEquals("10.05", results.getString(1)); - assertTrue(results.next()); - assertEquals("9.5", results.getString(1)); - assertFalse(results.next()); - } - else { - checkDecimal(1005, 2, results.getBigDecimal(1)); - assertTrue(results.next()); - checkDecimal(950, 1, results.getBigDecimal(1)); - assertFalse(results.next()); - } - } - - public void testStringToFromDecimalColumn() throws Exception { - execute("create table foo(x decimal(10,2))"); - - String insertString = "insert into foo(x) values('9.5')"; - if (dialect.canMixStringAndInteger()) { - execute(insertString); - } - else { - expectExecuteFailure(insertString, - "attempt to store string '9.5' into decimal column x"); - execute("insert into foo(x) values(9.5)"); - } - - PreparedStatement statement = connection.prepareStatement( - "insert into foo(x) values(?)"); - statement.setString(1, "10.05"); - if (dialect.canSetStringOnDecimalColumn()) { - statement.executeUpdate(); - } - else { - try { - statement.executeUpdate(); - fail(); - } - catch (SQLException e) { - assertMessage( - "attempt to store string '10.05' into decimal column x", e); - } - execute("insert into foo(x) values(10.05)"); - } - - ResultSet results = query("select x from foo order by x"); - - assertTrue(results.next()); - if (dialect.expectMayflyBehavior()) { - try { - results.getString(1); - fail(); - } - catch (SQLException e) { - assertMessage("attempt to read decimal 9.50 as a string", e); - } - checkDecimal(950, 2, results.getBigDecimal(1)); - assertTrue(results.next()); - checkDecimal(1005, 2, results.getBigDecimal(1)); - assertFalse(results.next()); - } - else { - assertEquals( - dialect.decimalScaleIsFromType() ? "9.50" : "9.5", - results.getString(1)); - assertTrue(results.next()); - assertEquals("10.05", results.getString(1)); - assertFalse(results.next()); - } - } - - public void testIntegerToFloat() throws Exception { - execute("create table foo (x bigint, y smallint)"); - // 4503599627370495 is, I believe, the largest integer value which can be - // represented exactly in a double. - execute("insert into foo(x, y) values (4503599627370495, 32767)"); - execute("insert into foo(x, y) values (-4503599627370495, -32767)"); - // Likewise for float: - execute("insert into foo(x, y) values (8388607, 0)"); - execute("insert into foo(x, y) values (-8388607, 0)"); - - ResultSet results = query("select x, y from foo"); - - assertTrue(results.next()); - assertEquals(32767.0, results.getDouble("y"), 0.00001); - assertEquals(4503599627370495.0, results.getDouble("x"), 0.00001); - assertEquals(32767.0f, results.getFloat("y"), 0.00001f); - /* Comparing as doubles rather than floats - better shows that bits are lost - (although we'd have to pick a different integer(s) to - delve into exactly how many bits are lost) */ - assertEquals(4503599627370495.0, results.getFloat("x"), 1.0); - - assertEquals(32767.0, results.getDouble(2), 0.00001); - assertEquals(32767.0f, results.getFloat(2), 0.00001f); - - assertTrue(results.next()); - assertEquals(- 4503599627370495.0, results.getDouble("x"), 0.00001); - assertEquals(- 32767.0f, results.getFloat("y"), 0.00001f); - - assertTrue(results.next()); - assertEquals(8388607.0f, results.getFloat("x"), 0.00001f); - - assertTrue(results.next()); - assertEquals(- 8388607.0f, results.getFloat("x"), 0.00001f); - - assertFalse(results.next()); - results.close(); - } - - public void testDecimalToFloat() throws Exception { - execute("create table foo (x decimal(10,3))"); - execute("insert into foo(x) values(53.904)"); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - assertEquals(53.904, results.getDouble("x"), 0.000001); - assertFalse(results.next()); - results.close(); - } - - public void testBinaryStream() throws Exception { - execute("create table foo (x " + dialect.binaryTypeName() + ")"); - - PreparedStatement insert = - connection.prepareStatement("insert into foo(x) values(?)"); - byte[] data = new byte[] { 0x1, 0x3, (byte)0xff, (byte)0x90 }; - /** - Requiring the correct length here probably wouldn't be - as big a deal as in the {@link StringTest#testCharacterStream} - case, although I guess there are cases (e.g. reading - from a network stream) in which it could be inconvenient. - */ - insert.setBinaryStream(1, new ByteArrayInputStream(data), data.length); - assertEquals(1, insert.executeUpdate()); - insert.close(); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - - InputStream stream = results.getBinaryStream(1); - byte[] contents = IOUtils.toByteArray(stream); - ArrayAssert.assertEquals(data, contents); - // We don't realy need to close it; the JDBC javadoc says that - // the next call to a getter method will close the stream - // for us. - stream.close(); - - byte[] viaBytes = results.getBytes("x"); - ArrayAssert.assertEquals(data, viaBytes); - - assertFalse(results.next()); - results.close(); - } - - public void testGetBlob() throws Exception { - execute("create table foo (x " + dialect.binaryTypeName() + ")"); - - PreparedStatement insert = - connection.prepareStatement("insert into foo(x) values(?)"); - byte[] data = new byte[] { 0x1, 0x3, (byte)0xff, (byte)0x90 }; - /** - Requiring the correct length here probably wouldn't be - as big a deal as in the {@link StringTest#testCharacterStream} - case, although I guess there are cases (e.g. reading - from a network stream) in which it could be inconvenient. - */ - insert.setBinaryStream(1, new ByteArrayInputStream(data), data.length); - // TODO: probably want to test setBlob while we're at it. -// insert.setBlob(1, blob); - assertEquals(1, insert.executeUpdate()); - insert.close(); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - - if (dialect.blobTypeWorks()) { - Blob blob = results.getBlob(1); - assertEquals(4L, blob.length()); - InputStream stream = blob.getBinaryStream(); - byte[] contents = IOUtils.toByteArray(stream); - ArrayAssert.assertEquals(data, contents); - // Do we need to close this? - stream.close(); - } - else { - try { - results.getBlob(1); - fail("Maybe postgres fixed their Blob bug?"); - } - catch (SQLException expected) { - } - } - - assertFalse(results.next()); - results.close(); - } - - public void testNumberAsBinary() throws Exception { - execute("create table foo(x integer)"); - execute("insert into foo(x) values(1)"); - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - if (!dialect.canGetBytesOnNumber()) { - try { - results.getBytes(1); - fail(); - } - catch (SQLException e) { - assertMessage("attempt to read number 1 as binary data", e); - } - } - else { - byte[] bytes = results.getBytes(1); - // 49 is the value of the character '1'. - ArrayAssert.assertEquals(new byte[] { 49 }, bytes); - } - } - - public void testNonBinaryInBinaryColumn() throws Exception { - execute("create table foo(x " + dialect.binaryTypeName() + ")"); - String insertOne = "insert into foo(x) values(1)"; - if (dialect.dataTypesAreEnforced()) { - expectExecuteFailure(insertOne, - "attempt to store number 1 into binary column x"); - assertResultSet(new String[] { }, query("select x from foo")); - } - else { - execute(insertOne); - assertResultSet(new String[] { " 1 " }, query("select x from foo")); - } - } - - public void testHexBinary() throws Exception { - /* TODO: Also should accept x'00' '01' '02' syntax which allows - a long hex literal to be continued over several lines */ - execute("create table foo(x " + dialect.binaryTypeName() + ")"); - String hexForBinary = "insert into foo(x) values(x'00010203ff7f00')"; - if (dialect.allowHexForBinary()) { - execute(hexForBinary); - execute("insert into foo(x) values (X'00')"); - - /** See {@link net.sourceforge.mayfly.parser.LexerTest#testHexErrors()} - for more tests of these error messages. */ - expectExecuteFailure("insert into foo(x) values(x'7ff')", - "hex constant x'7ff' must have an even number of digits"); - expectExecuteFailure("insert into foo(x) values(x'0g')", - "invalid character 'g' in hex constant"); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - ArrayAssert.assertEquals( - new byte[] { 0, 1, 2, 3, (byte)0xff, (byte)0x7f, 0 }, - results.getBytes(1)); - assertTrue(results.next()); - ArrayAssert.assertEquals( - new byte[] { 0 }, - results.getBytes(1)); - assertFalse(results.next()); - } - else { - expectExecuteFailure(hexForBinary, - "expected expression but got x'00010203ff7f00'"); - } - } - - public void testNullInBinaryColumn() throws Exception { - execute("create table foo(x " + dialect.binaryTypeName() + ")"); - execute("insert into foo(x) values(null)"); - assertResultSet(new String[] { " null " }, - query("select x from foo")); - - ResultSet results = query("select x from foo"); - assertTrue(results.next()); - byte[] bytes = results.getBytes("x"); - assertNull(bytes); - assertTrue(results.wasNull()); - assertFalse(results.next()); - results.close(); - } - - public void xtestBinaryAsPrimaryKey() throws Exception { - /* Derby: this is an error because comparisons are not - supported (could also check ORDER BY or <) */ - execute("create table foo(x " + dialect.binaryTypeName() + - " primary key)"); - PreparedStatement insert = - connection.prepareStatement("insert into foo(x) values(?)"); - insert.setBytes(1, new byte[] { 0x1, 0x3, (byte)0xff, (byte)0x90 }); - assertEquals(1, insert.executeUpdate()); - insert.setBytes(1, new byte[] { 0x1 }); - assertEquals(1, insert.executeUpdate()); - insert.close(); - } - -} Deleted: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DateTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DateTest.java 2008-04-26 19:34:45 UTC (rev 556) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DateTest.java 2008-05-01 04:46:45 UTC (rev 557) @@ -1,376 +0,0 @@ -package net.sourceforge.mayfly.acceptance; - -import org.joda.time.DateMidnight; -import org.joda.time.DateTime; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.Calendar; -import java.util.TimeZone; - -public class DateTest extends SqlTestCase { - - // DATE (see testDate), TIME, TIMESTAMP - // TIME WITH TIME ZONE is questionable (see postgres docs) - - private static final long ONE_SECOND = 1000L; - private static final long ONE_MINUTE = ONE_SECOND * 60L; - private static final long ONE_HOUR = ONE_MINUTE * 60L; - private static final long ONE_DAY = ONE_HOUR * 24L; - - /** How long the test might execute between saving an approximate - expected "current" time and actually reading the current time. - Normally, a second or a few would tend to suffice, but given the - possibility of stopping/resuming a test run with SIGSTOP, laptop suspend, - or similar mechanisms, one could argue - for values up to days. An hour seems like a reasonable compromise. */ - private static final long HOW_LONG_A_TEST_MIGHT_TAKE = ONE_HOUR; - /** If the database server is on another machine, any difference between - the clocks of the machines would need to be included here. If the - database reads the clock with, say, one second granularity and - the test gets millisecond granularity, then up to a second might need - to be included (depending on rounding). */ - private static final long HOW_MUCH_CURRENT_TIMESTAMP_MIGHT_BE_IN_THE_PAST = - ONE_MINUTE; - - private static final long NOVEMBER_27_UTC = 1069891200000L; - private static final long NOVEMBER_29_UTC = NOVEMBER_27_UTC + 2 * ONE_DAY; - - public void testDatePassUtcCalendar() throws Exception { - execute("create table foo (start_date date, end_date date)"); - execute("insert into foo (start_date, end_date) " + - "values ('2003-11-27', '2003-11-29')"); - - { - Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - ResultSet results = query("select start_date, end_date from foo"); - assertTrue(results.next()); - - assertDate(NOVEMBER_27_UTC, results.getDate(1, utc).getTime()); - assertDate(NOVEMBER_29_UTC, results.getDate("end_date", utc).getTime()); - - assertFalse(results.next()); - results.close(); - } - - // TODO: setDate, calendar and non-calendar - // TODO: getObject - // TODO: getDate on non-date - // TODO: default '2004-07-27' - // TODO: SQL92 literal syntax: date '2003-11-27' as in - //execute("insert into foo (start_date, end_date) - // values (date '2003-11-27', date '2003-11-29')"); - } - - public void testDatePassNonUtcCalendar() throws Exception { - execute("create table foo (start_date date, end_date date)"); - execute("insert into foo (start_date, end_date) " + - "values ('2003-11-27', '2003-11-29')"); - - // Like previous test but non-UTC - Calendar indianTime = - Calendar.getInstance(TimeZone.getTimeZone("GMT+0530")); - ResultSet results = query("select start_date, end_date from foo"); - assertTrue(results.next()); - - // Midnight Indian time is 5 1/2 hours earlier than - // midnight UTC. - long november27indian = NOVEMBER_27_UTC - - (5 * ONE_HOUR + 30 * ONE_MINUTE); - long november29indian = november27indian + 2 * ONE_DAY; - assertDate(november27indian, - results.getDate(1, indianTime).getTime()); - assertDate(november29indian, - results.getDate("end_date", indianTime).getTime()); - - assertFalse(results.next()); - results.close(); - } - - public void testNull() throws Exception { - execute("create table foo (start_date date, end_date date)"); - execute("insert into foo (start_date) values (null)"); - - // In this case we are reading as ints (or strings, I forget) - assertResultSet(new String[] { " null, null " }, - query("select start_date, end_date from foo")); - - // More interesting is to read as dates - ResultSet results = query("select start_date, end_date from foo"); - assertTrue(results.next()); - assertNull(results.getDate("start_date")); - Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - assertNull(results.getDate(2, utc)); - assertFalse(results.next()); - } - - public void testNullTimestamp() throws Exception { - execute("create table foo (x timestamp, y timestamp)"); - execute("insert into foo (x) values (null)"); - - { - // Read as strings - ResultSet results = query("select x, y from foo"); - assertTrue(results.next()); - - if (dialect.timestampDoesNotRespectNull()) { - // insert null seems to be a synonym for - // insert CURRENT_TIMESTAMP - assertTrue(results.getString("x").startsWith("20")); - assertFalse(results.wasNull()); - - /* y is the MySQL zero date. Trying to read it - with getString throws an exception... */ - assertEquals(0, results.getInt(2)); - assertFalse(results.wasNull()); - } - else { - assertEquals(null, results.getString("x")); - assertTrue(results.wasNull()); - - assertEquals(null, results.getString(2)); - assertTrue(results.wasNull()); - } - - assertFalse(results.next()); - } - - if (dialect.timestampDoesNotRespectNull()) { - return; - } - - { - // More interesting is to read as timestamps - ResultSet results = query("select x, y from foo"); - assertTrue(results.next()); - - assertEquals(null, results.getTimesta... [truncated message content] |
From: <ki...@us...> - 2008-04-26 19:34:50
|
Revision: 556 http://mayfly.svn.sourceforge.net/mayfly/?rev=556&view=rev Author: kingdon Date: 2008-04-26 12:34:45 -0700 (Sat, 26 Apr 2008) Log Message: ----------- Add H2 to acceptance test suite and set up expectations accordingly. Modified Paths: -------------- trunk/mayfly/.classpath trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AggregateTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DerbyDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropColumnTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ExpressionTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ForeignKeyTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MayflyDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/OrderByTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/SqlTestCase.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java trunk/mayfly/test/net/sourceforge/mayfly/acceptance/TransactionTest.java Added Paths: ----------- trunk/mayfly/test/lib/h2-1.0.71.jar trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java Modified: trunk/mayfly/.classpath =================================================================== --- trunk/mayfly/.classpath 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/.classpath 2008-04-26 19:34:45 UTC (rev 556) @@ -15,5 +15,6 @@ <classpathentry kind="lib" path="test/lib/hsqldb-1.8.0.7.jar" sourcepath="test/lib-src/hsqldb_1_8_0_7.zip"/> <classpathentry kind="lib" path="test/lib/junit-4.4.jar"/> <classpathentry kind="lib" path="test/lib/junit-addons-1.4.jar"/> + <classpathentry kind="lib" path="test/lib/h2-1.0.71.jar"/> <classpathentry kind="output" path="bin"/> </classpath> Added: trunk/mayfly/test/lib/h2-1.0.71.jar =================================================================== (Binary files differ) Property changes on: trunk/mayfly/test/lib/h2-1.0.71.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AddUniqueTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -86,7 +86,7 @@ expectExecuteFailure(add, "primary key id cannot be null"); execute("update foo set id = 7 where x = 20"); - if (dialect.uniqueColumnMayBeNullable()) { + if (dialect.canTurnNullableColumnIntoPrimaryKey()) { execute(add); expectExecuteFailure("insert into foo values(5, 30)", Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AggregateTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AggregateTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/AggregateTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -204,7 +204,7 @@ execute("insert into foo (x, y) values (7, 90)"); assertResultSet(new String[] { " 3 " }, - query("select count(all x) from foo")); + query("select count(x) from foo")); assertResultSet(new String[] { " 2 " }, query("select count(distinct x) from foo")); @@ -223,14 +223,25 @@ execute("insert into foo (x, y) values (5, 90)"); execute("insert into foo (x, y) values (7, 90)"); - 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")); + 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 { Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DataTypeTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -91,18 +91,15 @@ assertTrue(results.next()); assertTypesOfRow(results); assertTrue(results.next()); - /* The interesting part about this is that all tested databases, - so far, base the returned type on the types in the expressions, - not the particular values from this execution. */ assertTypesOfRow(results); assertFalse(results.next()); } private void assertTypesOfRow(ResultSet results) throws SQLException { ObjectAssert.assertInstanceOf( - dialect.typeOfInteger(), results.getObject("x")); + dialect.typeOfTinyint(), results.getObject("x")); ObjectAssert.assertInstanceOf( - dialect.typeOfInteger(), results.getObject("y")); + dialect.typeOfSmallint(), results.getObject("y")); ObjectAssert.assertInstanceOf( dialect.typeOfInteger(), results.getObject("z")); ObjectAssert.assertInstanceOf(Long.class, results.getObject("w")); Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DerbyDialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DerbyDialect.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DerbyDialect.java 2008-04-26 19:34:45 UTC (rev 556) @@ -70,6 +70,11 @@ } @Override + public boolean canTurnNullableColumnIntoPrimaryKey() { + return false; + } + + @Override public boolean canSetObjectNull() { return false; } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java 2008-04-26 19:34:45 UTC (rev 556) @@ -91,6 +91,10 @@ return true; } + public boolean detectsAmbiguousColumnsInOrderBy() { + return true; + } + /** * @internal * Should a test look for behavior in which Mayfly intentionally diverges @@ -144,6 +148,10 @@ return false; } + public boolean allowDuplicateTableWithDifferingColumnNames() { + return false; + } + public boolean detectsSyntaxErrorsInPrepareStatement() { return true; } @@ -173,12 +181,21 @@ } public boolean callJavaMethodAsStoredProcedure() { + // Not even H2 supports this syntax. So maybe there is a better way. return true; } + public boolean haveCreateAlias() { + return callJavaMethodAsStoredProcedure(); + } + public boolean complainAboutDubiousStoredProcedure() { return true; } + + public boolean complainAboutStoredProcedureOverloadingOnArgumentType() { + return true; + } public boolean orderByCountsAsWhat() { return false; @@ -206,6 +223,14 @@ return false; } + public boolean haveConcatBuiltInWithOneArgument() { + return false; + } + + public boolean haveConcatBuiltInWithZeroArguments() { + return false; + } + public boolean caseExpressionPickyAboutTypes() { return false; } @@ -264,17 +289,25 @@ return false; } - public boolean errorIfNotAggregateOrGrouped() { + public boolean errorIfNotAggregateOrGrouped(boolean rowsPresent) { return true; } + + public boolean disallowHavingOnUnaggregated() { + return true; + } - public boolean errorIfNotAggregateOrGroupedWhenGroupByExpression() { - return errorIfNotAggregateOrGrouped(); + public boolean errorIfNotAggregateOrGroupedWhenGroupByExpression(boolean rowsPresent) { + return errorIfNotAggregateOrGrouped(rowsPresent); } public boolean canGroupByExpression() { return true; } + + public boolean groupByExpressionSimpleComparator() { + return false; + } public boolean canOrderByExpression(boolean isAggregate) { return false; @@ -287,6 +320,10 @@ public boolean allowCountDistinctStar() { return false; } + + public boolean allowExplicitAllInAggregate() { + return true; + } public boolean canQuoteIdentifiers() { return true; @@ -388,6 +425,10 @@ return true; } + public boolean canTurnNullableColumnIntoPrimaryKey() { + return true; + } + public boolean allowMultipleNullsInUniqueColumn() { /* Most databases which allow nulls in unique columns allow more than one null (which is what this setting means @@ -472,6 +513,10 @@ public boolean willWaitForWriterToCommit() { return false; } + + public boolean willWaitForWriterToCommitOnTwoRowInserts() { + return false; + } public boolean haveForUpdate() { return true; @@ -511,6 +556,14 @@ return false; } + public boolean canDropTargetOfForeignKey() { + return false; + } + + public boolean foreignKeyMustReferToPrimaryKeyOrUnique() { + return true; + } + public boolean haveCheckConstraints() { return true; } @@ -531,7 +584,15 @@ // Obvious question here is what about overflow? return Long.class; } + + public Class typeOfTinyint() { + return Integer.class; + } + public Class typeOfSmallint() { + return Integer.class; + } + public Class typeOfInteger() { return Integer.class; } @@ -591,6 +652,10 @@ return true; } + public boolean canDropPrimaryKeyColumn() { + return true; + } + public boolean canDropColumnWithForeignKey() { return true; } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropColumnTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropColumnTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/DropColumnTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -64,12 +64,15 @@ } public void testSingleColumnPrimaryKey() throws Exception { - if (!dialect.haveDropColumn()) { - return; + execute("create table foo(a integer, b integer, primary key(a) )"); + String dropPrimaryKey = "alter table foo drop column a"; + if (dialect.haveDropColumn() && dialect.canDropPrimaryKeyColumn()) { + execute(dropPrimaryKey); } - - execute("create table foo(a integer, b integer, primary key(a) )"); - execute("alter table foo drop column a"); + else { + expectExecuteFailure(dropPrimaryKey, + "cannot drop column a because it is referenced by a primary key"); + } } public void testForeignKeyFromDroppedColumn() throws Exception { Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ExpressionTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ExpressionTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ExpressionTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -72,17 +72,38 @@ String query = "select concat(first_name, ' ', last_name) from names"; if (dialect.haveConcatBuiltIn()) { assertResultSet(new String[] { " 'John Jones' " }, query(query)); - - // Corner cases: one argument, or zero. - assertResultSet(new String[] { " 'John' " }, - query("select concat(first_name) from names")); - expectQueryFailure("select concat() from names", - "expected expression but got ')'"); } else { expectQueryFailure(query, "no function concat"); } } + public void testConcatBuiltInWithOneArgument() throws Exception { + execute("create table names (first_name varchar(255), last_name varchar(255))"); + execute("insert into names(first_name, last_name) values ('John', 'Jones')"); + String concatOneArgument = "select concat(first_name) from names"; + if (dialect.haveConcatBuiltInWithOneArgument()) { + assertResultSet(new String[] { " 'John' " }, + query(concatOneArgument)); + } else { + expectQueryFailure(concatOneArgument, + "concat requires 2 or more arguments" /* or no function concat */); + } + } + + public void testConcatBuiltInWithZeroArguments() throws Exception { + execute("create table names (first_name varchar(255), last_name varchar(255))"); + execute("insert into names(first_name, last_name) values ('John', 'Jones')"); + String concatZeroArguments = "select concat() from names"; + if (dialect.haveConcatBuiltInWithZeroArguments()) { + assertResultSet(new String[] { " null " }, + query(concatZeroArguments)); + } + else { + expectQueryFailure(concatZeroArguments, + "expected expression but got ')'"); + } + } + public void testNoSuchBuiltIn() throws Exception { execute("create table foo(x integer)"); expectExecuteFailure("insert into foo(x) values(ZETA_FUNCTION(5))", Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ForeignKeyTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ForeignKeyTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/ForeignKeyTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -117,11 +117,17 @@ ")" + dialect.tableTypeForForeignKeys()); - expectExecuteFailure("drop table countries", - "cannot drop countries because " + - "a foreign key in table cities refers to it"); - execute("drop table cities"); - execute("drop table countries"); + if (dialect.canDropTargetOfForeignKey()) { + execute("drop table countries"); + execute("insert into cities(name, country) values('India', 5)"); + } + else { + expectExecuteFailure("drop table countries", + "cannot drop countries because " + + "a foreign key in table cities refers to it"); + execute("drop table cities"); + execute("drop table countries"); + } } public void testDropTableWithSchemas() throws Exception { @@ -142,9 +148,15 @@ dialect.tableTypeForForeignKeys()); execute("set schema landoj"); - expectExecuteFailure("drop table countries", - "cannot drop countries because " + - "a foreign key in table urboj.cities refers to it"); + if (dialect.canDropTargetOfForeignKey()) { + execute("drop table countries"); + return; + } + else { + expectExecuteFailure("drop table countries", + "cannot drop countries because " + + "a foreign key in table urboj.cities refers to it"); + } execute("set schema urboj"); expectExecuteFailure("drop table landoj.countries", @@ -416,10 +428,16 @@ public void testNoPrimaryKeyOrUnique() throws Exception { execute("create table foo(id integer)" + dialect.tableTypeForForeignKeys()); - expectExecuteFailure("create table bar(" + - "foo_id integer, foreign key (foo_id) references foo(id))" - + dialect.tableTypeForForeignKeys(), - "foreign key refers to foo(id) which is not unique or a primary key"); + String referToNonUniqueOrPrimaryKey = "create table bar(" + + "foo_id integer, foreign key (foo_id) references foo(id))" + + dialect.tableTypeForForeignKeys(); + if (dialect.foreignKeyMustReferToPrimaryKeyOrUnique()) { + expectExecuteFailure(referToNonUniqueOrPrimaryKey, + "foreign key refers to foo(id) which is not unique or a primary key"); + } + else { + execute(referToNonUniqueOrPrimaryKey); + } } public void testReferencedColumnHasAnotherForeignKey() throws Exception { Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/GroupByTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -37,7 +37,7 @@ String needsSmartExpressionComparator = "select birthdate + age + 0 from people group by birthdate + age"; - if (dialect.expectMayflyBehavior()) { + if (dialect.groupByExpressionSimpleComparator()) { expectQueryFailure(needsSmartExpressionComparator, "expression is not aggregate or mentioned in GROUP BY"); } @@ -71,7 +71,7 @@ String expressionWhichMakesNoSense = "select birthdate - age from people group by birthdate + age"; - if (dialect.errorIfNotAggregateOrGroupedWhenGroupByExpression()) { + if (dialect.errorIfNotAggregateOrGroupedWhenGroupByExpression(false)) { expectQueryFailure( selectColumnNotGrouped, "age is not aggregate or mentioned in GROUP BY" @@ -165,7 +165,7 @@ String notAggegateOrGrouped = "select author, title, count(*) from books group by author order by author"; - if (dialect.errorIfNotAggregateOrGrouped()) { + if (dialect.errorIfNotAggregateOrGrouped(true)) { expectQueryFailure(notAggegateOrGrouped, "title is not aggregate or mentioned in GROUP BY"); } else { @@ -187,7 +187,7 @@ String notAggregateOrGrouped = "select author, title, count(*) from books group by author"; - if (dialect.errorIfNotAggregateOrGrouped()) { + if (dialect.errorIfNotAggregateOrGrouped(false)) { expectQueryFailure(notAggregateOrGrouped, "title is not aggregate or mentioned in GROUP BY"); } else { @@ -334,8 +334,14 @@ public void testHavingIsDisallowedOnUnaggregated() throws Exception { execute("create table foo (x integer, y integer)"); - expectQueryFailure("select avg(x) from foo group by y having x < 5", - "x is not aggregate or mentioned in GROUP BY"); + String sql = "select avg(x) from foo group by y having x < 5"; + if (dialect.disallowHavingOnUnaggregated()) { + expectQueryFailure(sql, + "x is not aggregate or mentioned in GROUP BY"); + } + else { + assertResultSet(new String[] { }, query(sql)); + } } public void testHavingWithoutGroupBy() throws Exception { @@ -378,7 +384,7 @@ String notAggregateOrGrouped = "select type, avg(price) from item " + "group by type order by price"; - if (dialect.errorIfNotAggregateOrGrouped()) { + if (dialect.errorIfNotAggregateOrGrouped(true)) { expectQueryFailure( notAggregateOrGrouped, "price is not aggregate or mentioned in GROUP BY"); @@ -396,7 +402,7 @@ String notAggregateOrGrouped = "select type, avg(price) from item " + "group by type order by price"; - if (dialect.errorIfNotAggregateOrGrouped()) { + if (dialect.errorIfNotAggregateOrGrouped(false)) { expectQueryFailure( notAggregateOrGrouped, "price is not aggregate or mentioned in GROUP BY"); @@ -437,7 +443,7 @@ String selectAll = "select * from books group by author"; String selectAllFromTable = "select books.* from books group by author"; - if (dialect.errorIfNotAggregateOrGrouped()) { + if (dialect.errorIfNotAggregateOrGrouped(true)) { expectQueryFailure(selectAll, "books.title is not aggregate or mentioned in GROUP BY"); expectQueryFailure(selectAllFromTable, @@ -475,7 +481,7 @@ String notAggregateOrGrouped = "select g.* from foo f, foo g group by f.a order by f.a"; - if (dialect.errorIfNotAggregateOrGroupedWhenGroupByExpression()) { + if (dialect.errorIfNotAggregateOrGroupedWhenGroupByExpression(true)) { expectQueryFailure(notAggregateOrGrouped, "g.a is not aggregate or mentioned in GROUP BY"); } Added: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java (rev 0) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/H2Dialect.java 2008-04-26 19:34:45 UTC (rev 556) @@ -0,0 +1,305 @@ +package net.sourceforge.mayfly.acceptance; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class H2Dialect extends Dialect { + + @Override + public Connection openConnection() throws Exception { + Class.forName("org.h2.Driver"); + return openAdditionalConnection(); + } + + @Override + public Connection openAdditionalConnection() throws SQLException { + return DriverManager.getConnection("jdbc:h2:mem:SqlTestCase"); + } + + @Override + public void shutdown(Connection connection) throws Exception { + SqlTestCase.execute("SHUTDOWN", connection); // So next test gets a new database. + } + + @Override + public Class typeOfTinyint() { + return Byte.class; + } + + @Override + public Class typeOfSmallint() { + return Short.class; + } + + @Override + public boolean expressionsAreTypeLong() { + return false; + } + + @Override + public boolean canMixStringAndInteger() { + return true; + } + + @Override + public boolean canSetStringOnDecimalColumn() { + return true; + } + + @Override + public boolean trailingSpacesConsultedInComparisons() { + return true; + } + + @Override + public boolean fromIsOptional() { + return true; + } + + @Override + public boolean quotedIdentifiersAreCaseSensitive() { + return true; + } + + @Override + public boolean callJavaMethodAsStoredProcedure() { + return false; + } + + @Override + public boolean haveCreateAlias() { + return true; + } + + @Override + public boolean complainAboutStoredProcedureOverloadingOnArgumentType() { + return false; + } + + @Override + public boolean canDropPrimaryKeyColumn() { + return false; + } + + @Override + public boolean canDropColumnWithForeignKey() { + return false; + } + + @Override + public boolean defaultValueCanBeExpression() { + return true; + } + + @Override + public boolean haveDropIndexOn() { + return false; + } + + @Override + public boolean allowTimestampInDateColumn() { + return true; + } + + @Override + public boolean allowDuplicateTableWithDifferingColumnNames() { + return true; + } + + @Override + public boolean innerJoinRequiresOn() { + return false; + } + + @Override + public boolean onIsRestrictedToJoinsTables() { + return false; + } + + @Override + public boolean considerTablesMentionedAfterJoin() { + return true; + } + + @Override + public boolean canDropTargetOfForeignKey() { + return true; + } + + @Override + public boolean foreignKeyMustReferToPrimaryKeyOrUnique() { + return false; + } + + @Override + public boolean foreignKeyJustNeedsIndex() { + return true; + } + + @Override + public boolean autoCommitMustBeOffToCallRollback() { + return false; + } + + @Override + public boolean willWaitForWriterToCommit() { + /* Although H2 does have a fairly short timeout, and we could look + for the timeout exception, it seems better + to not slow down the tests with timeouts. */ + return true; + } + + @Override + public boolean willWaitForWriterToCommitOnTwoRowInserts() { + return true; + } + + @Override + public boolean authorizationAllowedInCreateSchema() { + /* Actually, H2 allows the syntax, but it seems to + expect the user to exist. */ + return false; + } + + @Override + public boolean canCreateSchemaAndTablesInSameStatement() { + return false; + } + + @Override + public boolean canOrderByExpression(boolean isAggregate) { + return true; + } + + @Override + public boolean detectsAmbiguousColumnsInOrderBy() { + return false; + } + + @Override + public boolean metaDataExpectsUppercase() { + return true; + } + + @Override + public String productName() { + return "H2"; + } + + @Override + public boolean disallowNullOnRightHandSideOfIn() { + return false; + } + + @Override + public boolean notRequiresBoolean() { + return false; + } + + @Override + public boolean whereCanReferToColumnAlias() { + return false; + } + + @Override + public boolean canGetValueViaExpressionName() { + return true; + } + + @Override + public boolean maySpecifyTableDotColumnToJdbc() { + return true; + } + + @Override + public boolean canHaveLimitWithoutOrderBy() { + return true; + } + + @Override + public boolean haveDropForeignKey() { + return false; + } + + @Override + public boolean haveModifyColumn() { + return false; + } + + @Override + public boolean haveConcatBuiltIn() { + return true; + } + + @Override + public boolean disallowNullsInExpressions() { + return false; + } + + @Override + public boolean haveAutoUnderbarIncrement() { + return true; + } + + @Override + public boolean haveAutoIncrementSerial() { + return true; + } + + @Override + public boolean haveIdentity() { + return true; + } + + @Override + public boolean haveSql2003AutoIncrement() { + return true; + } + + @Override + public boolean sql2003RelativeToLastValue() { + return true; + } + + @Override + public boolean allowOrderByOnDelete() { + return false; + } + + @Override + public boolean canGroupByColumnAlias() { + return false; + } + + @Override + public boolean groupByExpressionSimpleComparator() { + return true; + } + + @Override + public boolean errorIfNotAggregateOrGrouped(boolean rowsPresent) { + if (rowsPresent) { + return true; + } + else { + return false; + } + } + + @Override + public boolean disallowHavingOnUnaggregated() { + return false; + } + + @Override + public boolean allowExplicitAllInAggregate() { + return false; + } + + @Override + public boolean canTurnNullableColumnIntoPrimaryKey() { + return false; + } + +} Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java 2008-04-26 19:34:45 UTC (rev 556) @@ -29,6 +29,11 @@ } @Override + public boolean detectsAmbiguousColumnsInOrderBy() { + return false; + } + + @Override public boolean crossJoinRequiresOn() { // In hypersonic, CROSS JOIN seems to be a synonym for INNER JOIN return true; @@ -50,6 +55,11 @@ } @Override + public boolean allowDuplicateTableWithDifferingColumnNames() { + return true; + } + + @Override public boolean rightHandArgumentToJoinCanBeJoin(boolean withParentheses) { return false; } @@ -115,7 +125,7 @@ } @Override - public boolean errorIfNotAggregateOrGroupedWhenGroupByExpression() { + public boolean errorIfNotAggregateOrGroupedWhenGroupByExpression(boolean rowsPresent) { return false; } @@ -338,4 +348,23 @@ return true; } + @Override + public boolean complainAboutStoredProcedureOverloadingOnArgumentType() { + return false; + } + + @Override + public boolean haveConcatBuiltInWithOneArgument() { + /* What is really going on here? Does an unrecognized function + have a defined behavior or something? */ + return true; + } + + @Override + public boolean haveConcatBuiltInWithZeroArguments() { + /* What is really going on here? Does an unrecognized function + have a defined behavior or something? */ + return true; + } + } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/JoinTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -189,8 +189,11 @@ execute("insert into bar(b) values(9)"); String sql = "select * from foo t, bar t"; - if (dialect.allowDuplicateTableInQuery()) { - assertResultSet(new String[] { " 5, 9 " }, query(sql)); + if (dialect.allowDuplicateTableWithDifferingColumnNames()) { + /* I guess it doesn't really matter whether the database + returns 5,5 or 5,9. Either way, accepting this seems + dubious. */ + query(sql); } else { expectQueryFailure(sql, "duplicate table name or alias t"); Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MayflyDialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MayflyDialect.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MayflyDialect.java 2008-04-26 19:34:45 UTC (rev 556) @@ -256,8 +256,18 @@ is a better syntax, seems like... */ return true; } - + @Override + public Class typeOfTinyint() { + return Long.class; + } + + @Override + public Class typeOfSmallint() { + return Long.class; + } + + @Override public Class typeOfInteger() { /* Is it important to be compatible with other databases (which have Integer.class here)? There's also a potential speed/space @@ -283,4 +293,19 @@ return true; } + @Override + public boolean haveConcatBuiltInWithOneArgument() { + /* Might make it easier to generate SQL automatically? + Not sure whether this is a real use case or an imaginary one. */ + return true; + } + + @Override + public boolean groupByExpressionSimpleComparator() { + /* Not sure whether this is worth worrying about or not, but maybe + in a different design catching the column which can't be evaluated + would just happen? Based on the H2 error message, it seems so. */ + return true; + } + } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/MySqlDialect.java 2008-04-26 19:34:45 UTC (rev 556) @@ -86,6 +86,11 @@ } @Override + public boolean haveConcatBuiltInWithOneArgument() { + return true; + } + + @Override public boolean tableNamesMightBeCaseSensitive() { // Whether table names are case sensitive in MySQL depends on whether // file names are. @@ -192,7 +197,7 @@ } @Override - public boolean errorIfNotAggregateOrGrouped() { + public boolean errorIfNotAggregateOrGrouped(boolean rowsPresent) { /* This is documented behavior. See the ONLY_FULL_GROUP_BY SQL mode to change it. */ return false; Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/OrderByTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/OrderByTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/OrderByTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -240,7 +240,7 @@ execute("CREATE TABLE foo (A INTEGER)"); execute("CREATE TABLE bar (A INTEGER)"); String sql = "select foo.a, bar.a from foo, bar order by a"; - if (dialect.detectsAmbiguousColumns()) { + if (dialect.detectsAmbiguousColumnsInOrderBy()) { expectQueryFailure(sql, "ambiguous column a"); } else { assertResultSet(new String[] { }, query(sql)); @@ -257,7 +257,7 @@ execute("insert into foo(a) values(53)"); String orderByWhenSelectingAggregate = "select count(a) from foo order by a"; - if (dialect.errorIfNotAggregateOrGrouped()) { + if (dialect.errorIfNotAggregateOrGrouped(true)) { expectQueryFailure(orderByWhenSelectingAggregate, "a is not aggregate or mentioned in GROUP BY"); } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/SqlTestCase.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/SqlTestCase.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/SqlTestCase.java 2008-04-26 19:34:45 UTC (rev 556) @@ -19,6 +19,7 @@ protected Dialect dialect = new MayflyDialect() + //new H2Dialect() //new HypersonicDialect() //new MySqlDialect() //new PostgresDialect() Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/StoredProcedureTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -26,7 +26,7 @@ "\"" + getClass().getName() + ".sampleProcedure\""; - if (dialect.callJavaMethodAsStoredProcedure()) { + if (dialect.haveCreateAlias()) { execute(createAlias); execute("create table foo(a integer, b integer)"); execute("insert into foo(a, b) values(2, 3)"); @@ -46,7 +46,7 @@ } public void testOverloadedOnArgumentCount() throws Exception { - if (!dialect.callJavaMethodAsStoredProcedure()) { + if (!dialect.haveCreateAlias()) { return; } @@ -77,7 +77,7 @@ } public void testOverloadedOnArgumentType() throws Exception { - if (!dialect.callJavaMethodAsStoredProcedure()) { + if (!dialect.haveCreateAlias()) { return; } @@ -85,7 +85,7 @@ execute("insert into foo(a) values(5)"); createAlias("onType"); String query = "select onType(a) from foo"; - if (dialect.complainAboutDubiousStoredProcedure()) { + if (dialect.complainAboutStoredProcedureOverloadingOnArgumentType()) { expectQueryFailure(query, "multiple methods found for stored procedure.\n" + "class: " + getClass().getName() + "\n" + @@ -108,7 +108,7 @@ } public void testWrongNumberOfArguments() throws Exception { - if (!dialect.callJavaMethodAsStoredProcedure()) { + if (!dialect.haveCreateAlias()) { return; } @@ -135,18 +135,24 @@ } public void testMethodNotStatic() throws Exception { - if (!dialect.callJavaMethodAsStoredProcedure()) { + if (!dialect.haveCreateAlias()) { return; } execute("create table foo(a integer)"); execute("insert into foo(a) values(5)"); - createAlias("notStatic"); + String query = "select notStatic(a) from foo"; - expectQueryFailure(query, - "stored procedure method must be static.\n" + + String expectedMessage = "stored procedure method must be static.\n" + "class: " + getClass().getName() + "\n" + - "method: notStatic"); + "method: notStatic"; + try { + createAlias("notStatic"); + query(query); + failForMissingException(query, expectedMessage); + } catch (SQLException e) { + assertMessage(expectedMessage, e); + } } public int notStatic(int a) { @@ -154,22 +160,28 @@ } public void testMethodNotPublic() throws Exception { - if (!dialect.callJavaMethodAsStoredProcedure()) { + if (!dialect.haveCreateAlias()) { return; } execute("create table foo(a integer)"); execute("insert into foo(a) values(5)"); - createAlias("notPublic"); + String query = "select notPublic(a) from foo"; + String expectedMessage = "stored procedure method must be public.\n" + + "class: " + getClass().getName() + "\n" + + "method: notPublic"; // Might be too much trouble to give a message other than "not found (maybe not public?)" - expectQueryFailure(query, - "stored procedure method must be public.\n" + - "class: " + getClass().getName() + "\n" + - "method: notPublic"); + try { + createAlias("notPublic"); + query(query); + failForMissingException(query, expectedMessage); + } catch (SQLException e) { + assertMessage(expectedMessage, e); + } } - int notPublic(int a) { + static int notPublic(int a) { return a; } Modified: trunk/mayfly/test/net/sourceforge/mayfly/acceptance/TransactionTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/acceptance/TransactionTest.java 2008-04-14 14:47:25 UTC (rev 555) +++ trunk/mayfly/test/net/sourceforge/mayfly/acceptance/TransactionTest.java 2008-04-26 19:34:45 UTC (rev 556) @@ -71,6 +71,9 @@ assertMessage("auto-commit must be off to call rollback", e); } } + else { + connection.rollback(); + } connection.setAutoCommit(false); connection.rollback(); @@ -139,6 +142,9 @@ } public void testTwoInsertsGetMerged() throws Exception { + if (dialect.willWaitForWriterToCommitOnTwoRowInserts()) { + return; + } execute("create table foo (x integer)"); Connection connection2 = dialect.openAdditionalConnection(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-04-14 14:47:36
|
Revision: 555 http://mayfly.svn.sourceforge.net/mayfly/?rev=555&view=rev Author: kingdon Date: 2008-04-14 07:47:25 -0700 (Mon, 14 Apr 2008) Log Message: ----------- More code to try to get resolve to work on dummy rows, before we are running through the real rows. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java Added Paths: ----------- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/EvaluatorTest.java Removed Paths: ------------- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java 2008-04-14 14:47:25 UTC (rev 555) @@ -57,7 +57,7 @@ abstract public boolean sameExpression(Expression other); - public Expression resolve(ResultRow row) { + public final Expression resolve(ResultRow row) { return resolve(row, Evaluator.NO_SUBSELECT_NEEDED); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/SingleColumn.java 2008-04-14 14:47:25 UTC (rev 555) @@ -127,7 +127,7 @@ @Override public Expression resolve(ResultRow row, Evaluator evaluator) { if (tableOrAlias == null) { - Expression lookedUp = evaluator.lookupName(columnName); + Expression lookedUp = evaluator.lookupName(row, columnName, location); if (lookedUp != null) { return lookedUp; } @@ -143,6 +143,22 @@ } } + /** + * @internal + * Low-level helper for {@link #resolve(ResultRow, Evaluator)} and + * related machinery. + */ + public SingleColumn asResultOfResolution(String spellingOfColumnName, + Location location2) { + if (!spellingOfColumnName.equalsIgnoreCase(columnName)) { + throw new MayflyInternalException( + "expected " + spellingOfColumnName + " and " + columnName + + " to differ only in case"); + } + return new SingleColumn(tableOrAlias, null, + spellingOfColumnName, location2, options); + } + @Override public void check(ResultRow row) { lookup(row); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java 2008-04-14 14:47:25 UTC (rev 555) @@ -50,12 +50,13 @@ } @Override - public Expression lookupName(String columnName) { + public Expression lookupName( + ResultRow row, String columnName, Location location) { Expression foundinWhat = what.lookupName(columnName); if (foundinWhat != null) { return foundinWhat; } - return delegate.lookupName(columnName); + return delegate.lookupName(row, columnName); } @Override Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/Evaluator.java 2008-04-14 14:47:25 UTC (rev 555) @@ -6,6 +6,7 @@ import net.sourceforge.mayfly.datastore.TableData; import net.sourceforge.mayfly.evaluation.Expression; import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.expression.SingleColumn; import net.sourceforge.mayfly.evaluation.from.FromTable; import net.sourceforge.mayfly.parser.Location; @@ -52,8 +53,24 @@ return new Options(); } - public Expression lookupName(String columnName) { + /** + * @internal + * row is usually (always?) a dummy row. The concept we are + * heading towards, as with + * {@link Expression#resolve(ResultRow, Evaluator)}, is that resolving + * names is part of an optimization/planning phase which happens + * once, not once for every row. + */ + public Expression lookupName(ResultRow row, String name, Location location) { + SingleColumn found = row.findColumnOrNull(null, name, location); + if (found != null) { + return found.asResultOfResolution(name, location); + } return null; } + public final Expression lookupName(ResultRow row, String name) { + return lookupName(row, name, Location.UNKNOWN); + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-04-14 14:47:25 UTC (rev 555) @@ -42,10 +42,13 @@ } @Override - public Expression lookupName(String columnName) { + public Expression lookupName( + ResultRow nonCorrelatedRow, String columnName, Location location) { Expression found = row.findColumnOrNull(null, columnName, Location.UNKNOWN); - return found; -// return nestedEvaluator.lookupName(columnName); + if (found != null) { + return found; + } + return nestedEvaluator.lookupName(nonCorrelatedRow, columnName); } @Override Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java 2008-04-14 14:47:25 UTC (rev 555) @@ -1,13 +1,13 @@ package net.sourceforge.mayfly.evaluation.select; +import static net.sourceforge.mayfly.util.MayflyAssert.assertAliasedColumn; import static net.sourceforge.mayfly.util.MayflyAssert.assertColumn; -import static net.sourceforge.mayfly.util.MayflyAssert.assertAliasedColumn; import junit.framework.TestCase; -import net.sourceforge.mayfly.Database; import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.datastore.LongCell; +import net.sourceforge.mayfly.datastore.NullCell; import net.sourceforge.mayfly.evaluation.NoColumn; import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.expression.SingleColumn; @@ -77,17 +77,20 @@ What what = new What( new AliasedExpression("john_smith", new SingleColumn("b")) ); - Database database = new Database(); - database.execute("create table foo(a integer, b integer)"); - database.execute("create table bar(john_smith integer)"); + ResultRow dummyRow = new ResultRow() + .withColumn("foo", "a", NullCell.INSTANCE) + .withColumn("foo", "b", NullCell.INSTANCE) + .withColumn("bar", "john_smith", NullCell.INSTANCE) + ; Evaluator evaluator = - new AliasEvaluator(what, new StoreEvaluator(database.dataStore())); + new AliasEvaluator(what, Evaluator.NO_SUBSELECT_NEEDED); // Not yet implemented (see StoreEvaluatorTest): -// assertColumn("foo", "a", evaluator.lookupName("a")); -// assertColumn("foo", "b", evaluator.lookupName("b")); - assertAliasedColumn("john_smith", null, "b", evaluator.lookupName("john_smith")); - assertNull(evaluator.lookupName("nonexist")); + assertColumn("foo", "a", evaluator.lookupName(dummyRow, "a")); + assertColumn("foo", "b", evaluator.lookupName(dummyRow, "b")); + assertAliasedColumn("john_smith", null, "b", + evaluator.lookupName(dummyRow, "john_smith")); + assertNull(evaluator.lookupName(dummyRow, "nonexist")); } } Copied: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/EvaluatorTest.java (from rev 554, trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java) =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/EvaluatorTest.java (rev 0) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/EvaluatorTest.java 2008-04-14 14:47:25 UTC (rev 555) @@ -0,0 +1,36 @@ +package net.sourceforge.mayfly.evaluation.select; + +import static net.sourceforge.mayfly.util.MayflyAssert.assertColumn; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import net.sourceforge.mayfly.MayflyException; +import net.sourceforge.mayfly.datastore.NullCell; +import net.sourceforge.mayfly.evaluation.ResultRow; + +import org.junit.Test; + + +public class EvaluatorTest { + + @Test + public void lookupName() { + ResultRow dummyRow = new ResultRow() + .withColumn("foo", "a", NullCell.INSTANCE) + .withColumn("foo", "b", NullCell.INSTANCE) + .withColumn("bar", "b", NullCell.INSTANCE) + ; + Evaluator evaluator = Evaluator.NO_SUBSELECT_NEEDED; + + assertColumn("foo", "a", evaluator.lookupName(dummyRow, "a")); + try { + evaluator.lookupName(dummyRow, "b"); + fail(); + } + catch (MayflyException e) { + assertEquals("ambiguous column b", e.getMessage()); + } + assertNull(evaluator.lookupName(dummyRow, "nosuch")); + } + +} Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-04-14 14:47:25 UTC (rev 555) @@ -46,11 +46,13 @@ @Test public void lookupName() { Evaluator nested = Evaluator.NO_SUBSELECT_NEEDED; + ResultRow nonCorrelatedRow = new ResultRow().withColumn("bbb", "b", new LongCell(8)); ResultRow correlatedRow = new ResultRow().withColumn("aaa", "a", new LongCell(7)); RowEvaluator evaluator = new RowEvaluator(correlatedRow, nested); - assertColumn("aaa", "a", evaluator.lookupName("a")); - assertNull(evaluator.lookupName("c")); + assertColumn("aaa", "a", evaluator.lookupName(nonCorrelatedRow, "a")); + assertColumn("bbb", "b", evaluator.lookupName(nonCorrelatedRow, "b")); + assertNull(evaluator.lookupName(nonCorrelatedRow, "c")); } } Deleted: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java 2008-04-14 03:49:39 UTC (rev 554) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java 2008-04-14 14:47:25 UTC (rev 555) @@ -1,40 +0,0 @@ -package net.sourceforge.mayfly.evaluation.select; - -import static net.sourceforge.mayfly.util.MayflyAssert.assertColumn; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; -import net.sourceforge.mayfly.Database; -import net.sourceforge.mayfly.MayflyException; - -import org.junit.Ignore; -import org.junit.Test; - - -public class StoreEvaluatorTest { - - /* Is the test right? Is this a property of tables or of joins, FROM, etc? - * A column name becomes non-ambiguous if that column isn't mentioned - * in this query, right? - * Seems like we usually implement this kind of thing with a dummy row. - */ - @Test - @Ignore - public void lookupName() { - Database database = new Database(); - database.execute("create table foo(a integer, b integer)"); - database.execute("create table bar(b integer)"); - Evaluator evaluator = new StoreEvaluator(database.dataStore()); - - assertColumn("foo", "a", evaluator.lookupName("a")); - try { - evaluator.lookupName("b"); - fail(); - } - catch (MayflyException e) { - assertEquals("ambiguous column b", e.getMessage()); - } - assertNull(evaluator.lookupName("nosuch")); - } - -} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-04-14 03:49:43
|
Revision: 554 http://mayfly.svn.sourceforge.net/mayfly/?rev=554&view=rev Author: kingdon Date: 2008-04-13 20:49:39 -0700 (Sun, 13 Apr 2008) Log Message: ----------- A few baby steps closer to being able to resolve HAVING. Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/CurrentTimestampExpression.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/StoreEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AliasedExpression.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java trunk/mayfly/test/net/sourceforge/mayfly/util/MayflyAssert.java Added Paths: ----------- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/Expression.java 2008-04-14 03:49:39 UTC (rev 554) @@ -2,6 +2,8 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.datastore.Row; +import net.sourceforge.mayfly.evaluation.expression.CurrentTimestampExpression; +import net.sourceforge.mayfly.evaluation.expression.literal.Literal; import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.evaluation.what.Selected; import net.sourceforge.mayfly.evaluation.what.WhatElement; @@ -79,6 +81,13 @@ return false; } + /** + * @internal + * Return a representation of this expression suitable for including in + * a database dump. Currently only needed, or implemented, for expressions + * which can be default values (or on-update values), like {@link Literal} or + * {@link CurrentTimestampExpression}. + */ public String asSql() { return evaluate((ResultRow) null).asSql(); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/CurrentTimestampExpression.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/CurrentTimestampExpression.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/expression/CurrentTimestampExpression.java 2008-04-14 03:49:39 UTC (rev 554) @@ -30,7 +30,7 @@ } private Cell valueAsCell() { - /* Note that the timezone here is the one of the current machine. */ + /* The timezone here is the one of the current machine. */ return new TimestampCell(new LocalDateTime(timeSource.current())); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/AliasEvaluator.java 2008-04-14 03:49:39 UTC (rev 554) @@ -51,7 +51,11 @@ @Override public Expression lookupName(String columnName) { - return what.lookupName(columnName); + Expression foundinWhat = what.lookupName(columnName); + if (foundinWhat != null) { + return foundinWhat; + } + return delegate.lookupName(columnName); } @Override Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-04-14 03:49:39 UTC (rev 554) @@ -4,6 +4,7 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.datastore.DataStore; import net.sourceforge.mayfly.datastore.TableData; +import net.sourceforge.mayfly.evaluation.Expression; import net.sourceforge.mayfly.evaluation.NoColumn; import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.from.FromTable; @@ -40,12 +41,12 @@ } } -// @Override -// public Expression lookupName(String columnName) { -// Expression found = row.findColumnOrNull(null, columnName, Location.UNKNOWN); -// return found; -//// return nestedEvaluator.lookupName(columnName); -// } + @Override + public Expression lookupName(String columnName) { + Expression found = row.findColumnOrNull(null, columnName, Location.UNKNOWN); + return found; +// return nestedEvaluator.lookupName(columnName); + } @Override public Options options() { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/StoreEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/StoreEvaluator.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/StoreEvaluator.java 2008-04-14 03:49:39 UTC (rev 554) @@ -13,6 +13,10 @@ private final DataStore store; private final String currentSchema; private Options options; + + public StoreEvaluator(DataStore store) { + this(store, DataStore.ANONYMOUS_SCHEMA_NAME); + } public StoreEvaluator(DataStore store, String currentSchema) { this(store, currentSchema, new Options()); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AliasedExpression.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AliasedExpression.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/what/AliasedExpression.java 2008-04-14 03:49:39 UTC (rev 554) @@ -14,8 +14,8 @@ */ public class AliasedExpression extends Expression { - private final String alias; - private final Expression expression; + public final String alias; + public final Expression expression; public AliasedExpression(String aliasedColumn, Expression expression) { this.alias = aliasedColumn; Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/AliasEvaluatorTest.java 2008-04-14 03:49:39 UTC (rev 554) @@ -1,7 +1,11 @@ package net.sourceforge.mayfly.evaluation.select; +import static net.sourceforge.mayfly.util.MayflyAssert.assertColumn; +import static net.sourceforge.mayfly.util.MayflyAssert.assertAliasedColumn; + import junit.framework.TestCase; +import net.sourceforge.mayfly.Database; import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.datastore.LongCell; import net.sourceforge.mayfly.evaluation.NoColumn; @@ -25,7 +29,6 @@ check(6, "a", evaluator, row); check(7, "b", evaluator, row); check(7, "john_smith", evaluator, row); - check(7, "john_smith", evaluator, row); try { check(787, "nonexist", evaluator, row); @@ -69,5 +72,22 @@ LongCell value = (LongCell) evaluator.lookup(row, table, column, null); assertEquals(expected, value.asLong()); } + + public void testLookupName() throws Exception { + What what = new What( + new AliasedExpression("john_smith", new SingleColumn("b")) + ); + Database database = new Database(); + database.execute("create table foo(a integer, b integer)"); + database.execute("create table bar(john_smith integer)"); + Evaluator evaluator = + new AliasEvaluator(what, new StoreEvaluator(database.dataStore())); + // Not yet implemented (see StoreEvaluatorTest): +// assertColumn("foo", "a", evaluator.lookupName("a")); +// assertColumn("foo", "b", evaluator.lookupName("b")); + assertAliasedColumn("john_smith", null, "b", evaluator.lookupName("john_smith")); + assertNull(evaluator.lookupName("nonexist")); + } + } Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-04-14 03:49:39 UTC (rev 554) @@ -49,7 +49,7 @@ ResultRow correlatedRow = new ResultRow().withColumn("aaa", "a", new LongCell(7)); RowEvaluator evaluator = new RowEvaluator(correlatedRow, nested); -// assertColumn("aaa", "a", evaluator.lookupName("a")); + assertColumn("aaa", "a", evaluator.lookupName("a")); assertNull(evaluator.lookupName("c")); } Added: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java (rev 0) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/StoreEvaluatorTest.java 2008-04-14 03:49:39 UTC (rev 554) @@ -0,0 +1,40 @@ +package net.sourceforge.mayfly.evaluation.select; + +import static net.sourceforge.mayfly.util.MayflyAssert.assertColumn; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import net.sourceforge.mayfly.Database; +import net.sourceforge.mayfly.MayflyException; + +import org.junit.Ignore; +import org.junit.Test; + + +public class StoreEvaluatorTest { + + /* Is the test right? Is this a property of tables or of joins, FROM, etc? + * A column name becomes non-ambiguous if that column isn't mentioned + * in this query, right? + * Seems like we usually implement this kind of thing with a dummy row. + */ + @Test + @Ignore + public void lookupName() { + Database database = new Database(); + database.execute("create table foo(a integer, b integer)"); + database.execute("create table bar(b integer)"); + Evaluator evaluator = new StoreEvaluator(database.dataStore()); + + assertColumn("foo", "a", evaluator.lookupName("a")); + try { + evaluator.lookupName("b"); + fail(); + } + catch (MayflyException e) { + assertEquals("ambiguous column b", e.getMessage()); + } + assertNull(evaluator.lookupName("nosuch")); + } + +} Modified: trunk/mayfly/test/net/sourceforge/mayfly/util/MayflyAssert.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/util/MayflyAssert.java 2008-04-07 22:30:07 UTC (rev 553) +++ trunk/mayfly/test/net/sourceforge/mayfly/util/MayflyAssert.java 2008-04-14 03:49:39 UTC (rev 554) @@ -1,7 +1,8 @@ package net.sourceforge.mayfly.util; -import junit.framework.Assert; - +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.datastore.LongCell; import net.sourceforge.mayfly.datastore.StringCell; @@ -12,19 +13,19 @@ import net.sourceforge.mayfly.evaluation.expression.SingleColumn; import net.sourceforge.mayfly.evaluation.expression.literal.IntegerLiteral; import net.sourceforge.mayfly.evaluation.expression.literal.QuotedString; +import net.sourceforge.mayfly.evaluation.what.AliasedExpression; import net.sourceforge.mayfly.parser.Location; public class MayflyAssert { public static void assertInteger(int expected, Expression actual) { IntegerLiteral ten = (IntegerLiteral) actual; - Assert.assertEquals(expected, ten.value); + assertEquals(expected, ten.value); } public static void assertString(String expected, Expression actual) { QuotedString string = (QuotedString) actual; - Assert.assertEquals(expected, string.stringWithoutQuotes()); - + assertEquals(expected, string.stringWithoutQuotes()); } public static void assertColumn(String expectedName, Expression expression) { @@ -34,10 +35,18 @@ public static void assertColumn(String expectedAlias, String expectedName, Expression expression) { SingleColumn y = (SingleColumn) expression; - Assert.assertEquals(expectedAlias, y.tableOrAlias()); - Assert.assertEquals(expectedName, y.columnName()); + assertEquals(expectedAlias, y.tableOrAlias()); + assertEquals(expectedName, y.columnName()); } + public static void assertAliasedColumn(String expectedAlias, + String expectedTable, String expectedName, + Expression expression) { + AliasedExpression aliased = (AliasedExpression) expression; + assertEquals(expectedAlias, aliased.alias); + assertColumn(expectedTable, expectedName, aliased.expression); + } + public static void assertColumn(String expectedColumn, int expectedValue, ResultRow row, int index) { assertColumn(expectedColumn, row.expression(index)); @@ -60,43 +69,43 @@ public static void assertLocation( int expectedStartColumn, int expectedEndColumn, Location location) { - Assert.assertEquals(expectedStartColumn, location.startColumn); - Assert.assertEquals(expectedEndColumn, location.endColumn); - Assert.assertEquals(1, location.startLineNumber); - Assert.assertEquals(1, location.endLineNumber); + assertEquals(expectedStartColumn, location.startColumn); + assertEquals(expectedEndColumn, location.endColumn); + assertEquals(1, location.startLineNumber); + assertEquals(1, location.endLineNumber); } public static void assertLocation( int startLineNumber, int startColumn, int endLineNumber, int endColumn, Location location) { - Assert.assertEquals(startLineNumber, location.startLineNumber); - Assert.assertEquals(startColumn, location.startColumn); - Assert.assertEquals(endLineNumber, location.endLineNumber); - Assert.assertEquals(endColumn, location.endColumn); + assertEquals(startLineNumber, location.startLineNumber); + assertEquals(startColumn, location.startColumn); + assertEquals(endLineNumber, location.endLineNumber); + assertEquals(endColumn, location.endColumn); } public static void assertLong(int expected, Cell actual) { LongCell cell = (LongCell) actual; - Assert.assertEquals(expected, cell.asLong()); + assertEquals(expected, cell.asLong()); } public static void assertString(String expected, Cell actual) { StringCell cell = (StringCell) actual; - Assert.assertEquals(expected, cell.asString()); + assertEquals(expected, cell.asString()); } public static void assertLessThan(Cell cell1, Cell cell2) { - Assert.assertFalse(cell1.sqlEquals(cell2)); - Assert.assertFalse(cell2.sqlEquals(cell1)); - Assert.assertTrue(cell1.compareTo(cell2) < 0); - Assert.assertTrue(cell2.compareTo(cell1) > 0); + assertFalse(cell1.sqlEquals(cell2)); + assertFalse(cell2.sqlEquals(cell1)); + assertTrue(cell1.compareTo(cell2) < 0); + assertTrue(cell2.compareTo(cell1) > 0); } public static void assertComparesSqlEqual(Cell cell1, Cell cell2) { - Assert.assertTrue(cell1.sqlEquals(cell2)); - Assert.assertTrue(cell2.sqlEquals(cell1)); - Assert.assertEquals(0, cell1.compareTo(cell2)); - Assert.assertEquals(0, cell2.compareTo(cell1)); + assertTrue(cell1.sqlEquals(cell2)); + assertTrue(cell2.sqlEquals(cell1)); + assertEquals(0, cell1.compareTo(cell2)); + assertEquals(0, cell2.compareTo(cell1)); } public static Cell coerce(DataType type, Cell cell) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-04-07 22:30:12
|
Revision: 553 http://mayfly.svn.sourceforge.net/mayfly/?rev=553&view=rev Author: kingdon Date: 2008-04-07 15:30:07 -0700 (Mon, 07 Apr 2008) Log Message: ----------- Now can resolve conditions as well as expressions. Closer to immutable objects in GroupByKeys, GroupBy. Part of the way to solving the test failure where HAVING refers to an aggregate (but the solution causes other problems, so it is commented out for now). Modified Paths: -------------- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupedRows.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRows.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/And.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Equal.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Greater.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/In.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/IsNull.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/LessEqual.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Like.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Not.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Or.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/SubselectedIn.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/True.java trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java trunk/mayfly/src/net/sourceforge/mayfly/util/L.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByTest.java trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupedRowsTest.java Added Paths: ----------- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupBy.java 2008-04-07 22:30:07 UTC (rev 553) @@ -5,20 +5,22 @@ import net.sourceforge.mayfly.evaluation.condition.Condition; import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.evaluation.what.Selected; +import net.sourceforge.mayfly.util.ImmutableList; public class GroupBy implements Aggregator { - private GroupByKeys keys = new GroupByKeys(); - private Condition having = Condition.TRUE; + private final GroupByKeys keys; + private Condition having; - public void add(GroupItem item) { - keys.add(item); + public GroupBy(ImmutableList<GroupItem> items, Condition having) { + keys = new GroupByKeys(items); + this.having = having; } - public void setHaving(Condition having) { - this.having = having; + public GroupBy(GroupItem... item) { + this(ImmutableList.fromArray(item), Condition.TRUE); } - + public GroupedRows makeGroupedRows(ResultRows resultRows, Evaluator evaluator) { GroupedRows grouped = new GroupedRows(); for (ResultRow row : resultRows) { @@ -33,6 +35,7 @@ } public ResultRow check(ResultRow afterJoins, Evaluator evaluator, Selected selected) { +// having = having.resolve(afterJoins, evaluator); keys.resolve(afterJoins, evaluator); GroupedRows grouped = makeGroupedRows(new ResultRows(afterJoins), evaluator); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupByKeys.java 2008-04-07 22:30:07 UTC (rev 553) @@ -2,19 +2,28 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.evaluation.select.Evaluator; +import net.sourceforge.mayfly.util.ImmutableList; import java.util.ArrayList; import java.util.Collections; import java.util.List; +/** + * @internal + * Not yet immutable, because of {@link GroupItem} + */ public class GroupByKeys { - private List<GroupItem> items = new ArrayList<GroupItem>(); + private final ImmutableList<GroupItem> items; - public void add(GroupItem key) { - items.add(key); + public GroupByKeys(GroupItem... items) { + this(ImmutableList.fromArray(items)); } + public GroupByKeys(ImmutableList<GroupItem> items) { + this.items = items; + } + List expressions() { List columns = new ArrayList(); for (GroupItem item : items) { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupedRows.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupedRows.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/GroupedRows.java 2008-04-07 22:30:07 UTC (rev 553) @@ -15,7 +15,7 @@ public class GroupedRows { private Map groups = new LinkedHashMap(); - private List/*<Expression>*/ keyColumns = null; + private List<Expression> keyColumns = null; private GroupByKeys keys; public int groupCount() { @@ -119,7 +119,7 @@ } for (int i = 0; i < cells.size(); ++i) { Cell cell = cells.get(i); - Expression expression = (Expression) keyColumns.get(i); + Expression expression = keyColumns.get(i); accumulator = accumulator.with(expression, cell); } return accumulator; Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/NoGroupBy.java 2008-04-07 22:30:07 UTC (rev 553) @@ -4,8 +4,6 @@ import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.evaluation.what.Selected; -import java.util.Iterator; - public class NoGroupBy implements Aggregator { public ResultRows group(ResultRows rows, Evaluator evaluator, Selected selected) { @@ -19,8 +17,7 @@ String firstColumn = null; String firstAggregate = null; - for (Iterator iter = selected.iterator(); iter.hasNext();) { - Expression element = (Expression) iter.next(); + for (Expression element : selected) { if (firstColumn == null) { firstColumn = element.firstColumn(); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRow.java 2008-04-07 22:30:07 UTC (rev 553) @@ -91,6 +91,16 @@ public SingleColumn findColumn(String tableOrAlias, String columnName, Location location) { + SingleColumn found = findColumnOrNull(tableOrAlias, columnName, location); + if (found == null) { + throw new NoColumn(tableOrAlias, columnName, location); + } else { + return found; + } + } + + public SingleColumn findColumnOrNull( + String tableOrAlias, String columnName, Location location) { SingleColumn found = null; for (Element element : elements) { if (element.expression instanceof SingleColumn) { @@ -107,11 +117,7 @@ } } } - if (found == null) { - throw new NoColumn(tableOrAlias, columnName, location); - } else { - return found; - } + return found; } public Cell findValue(Expression target) { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRows.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRows.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/ResultRows.java 2008-04-07 22:30:07 UTC (rev 553) @@ -65,7 +65,7 @@ } return selected; } - + public ResultRows join(ResultRows right) { List result = new ArrayList(); for (Iterator leftIterator = iterator(); leftIterator.hasNext();) { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/And.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/And.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/And.java 2008-04-07 22:30:07 UTC (rev 553) @@ -29,6 +29,18 @@ return leftSide.evaluate(row, evaluator) && rightSide.evaluate(row, evaluator); } + + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Condition newLeftSide = leftSide.resolve(row, evaluator); + Condition newRightSide = rightSide.resolve(row, evaluator); + if (newLeftSide != leftSide || newRightSide != rightSide) { + return new And(newLeftSide, newRightSide); + } + else { + return this; + } + } @Override public String firstAggregate() { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Condition.java 2008-04-07 22:30:07 UTC (rev 553) @@ -27,6 +27,8 @@ } abstract public boolean evaluate(ResultRow row, Evaluator evaluator); + + abstract public Condition resolve(ResultRow row, Evaluator evaluator); abstract public String firstAggregate(); Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Equal.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Equal.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Equal.java 2008-04-07 22:30:07 UTC (rev 553) @@ -2,6 +2,8 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.evaluation.Expression; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.select.Evaluator; public class Equal extends RowExpression { @@ -14,4 +16,16 @@ return leftSide.sqlEquals(rightSide); } + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Expression newLeftSide = leftSide.resolve(row, evaluator); + Expression newRightSide = rightSide.resolve(row, evaluator); + if (newLeftSide != leftSide || newRightSide != rightSide) { + return new Equal(newLeftSide, newRightSide); + } + else { + return this; + } + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Greater.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Greater.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Greater.java 2008-04-07 22:30:07 UTC (rev 553) @@ -2,6 +2,8 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.evaluation.Expression; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.select.Evaluator; public class Greater extends RowExpression { @@ -14,4 +16,16 @@ return leftSide.compareTo(rightSide) > 0; } + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Expression newLeftSide = leftSide.resolve(row, evaluator); + Expression newRightSide = rightSide.resolve(row, evaluator); + if (newLeftSide != leftSide || newRightSide != rightSide) { + return new Greater(newLeftSide, newRightSide); + } + else { + return this; + } + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/In.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/In.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/In.java 2008-04-07 22:30:07 UTC (rev 553) @@ -5,6 +5,7 @@ import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.util.ImmutableList; +import net.sourceforge.mayfly.util.L; public class In extends Condition { @@ -28,6 +29,31 @@ } return false; } + + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + boolean resolvedSomething = false; + Expression newLeftSide = leftSide.resolve(row, evaluator); + if (newLeftSide != leftSide) { + resolvedSomething = true; + } + + L<Expression> newRightSide = new L<Expression>(); + for (Expression aRightSide : expressions) { + Expression resolved = aRightSide.resolve(row, evaluator); + if (resolved != aRightSide) { + resolvedSomething = true; + } + newRightSide.add(resolved); + } + + if (resolvedSomething) { + return new In(newLeftSide, newRightSide.asImmutable()); + } + else { + return this; + } + } @Override public String firstAggregate() { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/IsNull.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/IsNull.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/IsNull.java 2008-04-07 22:30:07 UTC (rev 553) @@ -19,6 +19,17 @@ Cell cell = expression.evaluate(row, evaluator); return cell instanceof NullCell; } + + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Expression resolved = expression.resolve(row, evaluator); + if (resolved != expression) { + return new IsNull(resolved); + } + else { + return this; + } + } @Override public String firstAggregate() { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/LessEqual.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/LessEqual.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/LessEqual.java 2008-04-07 22:30:07 UTC (rev 553) @@ -2,6 +2,8 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.evaluation.Expression; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.select.Evaluator; public class LessEqual extends RowExpression { @@ -14,4 +16,16 @@ return leftSide.compareTo(rightSide) <= 0; } + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Expression newLeftSide = leftSide.resolve(row, evaluator); + Expression newRightSide = rightSide.resolve(row, evaluator); + if (newLeftSide != leftSide || newRightSide != rightSide) { + return new LessEqual(newLeftSide, newRightSide); + } + else { + return this; + } + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Like.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Like.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Like.java 2008-04-07 22:30:07 UTC (rev 553) @@ -3,6 +3,8 @@ import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.datastore.NullCell; import net.sourceforge.mayfly.evaluation.Expression; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.evaluation.select.Evaluator; import java.util.regex.Pattern; @@ -50,4 +52,16 @@ ; } + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Expression newLeftSide = leftSide.resolve(row, evaluator); + Expression newRightSide = rightSide.resolve(row, evaluator); + if (newLeftSide != leftSide || newRightSide != rightSide) { + return new Like(newLeftSide, newRightSide); + } + else { + return this; + } + } + } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Not.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Not.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Not.java 2008-04-07 22:30:07 UTC (rev 553) @@ -18,6 +18,17 @@ } @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Condition newOperand = operand.resolve(row, evaluator); + if (newOperand != operand) { + return new Not(operand); + } + else { + return this; + } + } + + @Override public String firstAggregate() { return operand.firstAggregate(); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Or.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Or.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/Or.java 2008-04-07 22:30:07 UTC (rev 553) @@ -20,6 +20,18 @@ } @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Condition newLeftSide = leftSide.resolve(row, evaluator); + Condition newRightSide = rightSide.resolve(row, evaluator); + if (newLeftSide != leftSide || newRightSide != rightSide) { + return new Or(newLeftSide, newRightSide); + } + else { + return this; + } + } + + @Override public String firstAggregate() { return firstAggregate(leftSide, rightSide); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/SubselectedIn.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/SubselectedIn.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/SubselectedIn.java 2008-04-07 22:30:07 UTC (rev 553) @@ -11,8 +11,8 @@ public class SubselectedIn extends Condition { + private final Expression leftSide; private final Select subselect; - private final Expression leftSide; public SubselectedIn(Expression leftSide, Select subselect) { this.leftSide = leftSide; @@ -34,6 +34,18 @@ } @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + Expression newLeftSide = leftSide.resolve(row, evaluator); + // Probably should be resolving the subselect too. + if (newLeftSide != leftSide) { + return new SubselectedIn(leftSide, subselect); + } + else { + return this; + } + } + + @Override public String firstAggregate() { return leftSide.firstAggregate(); } Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/True.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/True.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/condition/True.java 2008-04-07 22:30:07 UTC (rev 553) @@ -9,6 +9,11 @@ public boolean evaluate(ResultRow candidate, Evaluator evaluator) { return true; } + + @Override + public Condition resolve(ResultRow row, Evaluator evaluator) { + return this; + } @Override public String firstAggregate() { Modified: trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/evaluation/select/RowEvaluator.java 2008-04-07 22:30:07 UTC (rev 553) @@ -40,6 +40,13 @@ } } +// @Override +// public Expression lookupName(String columnName) { +// Expression found = row.findColumnOrNull(null, columnName, Location.UNKNOWN); +// return found; +//// return nestedEvaluator.lookupName(columnName); +// } + @Override public Options options() { return nestedEvaluator.options(); Modified: trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/parser/Parser.java 2008-04-07 22:30:07 UTC (rev 553) @@ -1,14 +1,13 @@ package net.sourceforge.mayfly.parser; +import static net.sourceforge.mayfly.parser.TokenType.CLOSE_PAREN; import static net.sourceforge.mayfly.parser.TokenType.EQUAL; -import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_column; import static net.sourceforge.mayfly.parser.TokenType.IDENTIFIER; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_character; +import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_column; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_on; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_set; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_values; -import static net.sourceforge.mayfly.parser.TokenType.CLOSE_PAREN; - import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.MayflyInternalException; import net.sourceforge.mayfly.Options; @@ -55,6 +54,7 @@ import net.sourceforge.mayfly.evaluation.command.Insert; import net.sourceforge.mayfly.evaluation.command.LastIdentity; import net.sourceforge.mayfly.evaluation.command.ModifyColumn; +import net.sourceforge.mayfly.evaluation.command.NoopCommand; import net.sourceforge.mayfly.evaluation.command.SetClause; import net.sourceforge.mayfly.evaluation.command.SetSchema; import net.sourceforge.mayfly.evaluation.command.SubselectedInsert; @@ -65,7 +65,6 @@ import net.sourceforge.mayfly.evaluation.command.UnresolvedTableReference; import net.sourceforge.mayfly.evaluation.command.UnresolvedUniqueConstraint; import net.sourceforge.mayfly.evaluation.command.Update; -import net.sourceforge.mayfly.evaluation.command.NoopCommand; import net.sourceforge.mayfly.evaluation.condition.And; import net.sourceforge.mayfly.evaluation.condition.Condition; import net.sourceforge.mayfly.evaluation.condition.Equal; @@ -1681,16 +1680,20 @@ private Aggregator parseGroupBy() { if (consumeIfMatches(TokenType.KEYWORD_group)) { expectAndConsume(TokenType.KEYWORD_by); - - GroupBy groupBy = new GroupBy(); + + List<GroupItem> items = new ArrayList<GroupItem>(); do { - groupBy.add(parseGroupItem()); + items.add(parseGroupItem()); } while (consumeIfMatches(TokenType.COMMA)); + Condition having; if (consumeIfMatches(TokenType.KEYWORD_having)) { - groupBy.setHaving(parseCondition().asBoolean()); + having = parseCondition().asBoolean(); } - return groupBy; + else { + having = Condition.TRUE; + } + return new GroupBy(new ImmutableList<GroupItem>(items), having); } else { if (currentToken.type == TokenType.KEYWORD_having) { Modified: trunk/mayfly/src/net/sourceforge/mayfly/util/L.java =================================================================== --- trunk/mayfly/src/net/sourceforge/mayfly/util/L.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/src/net/sourceforge/mayfly/util/L.java 2008-04-07 22:30:07 UTC (rev 553) @@ -1,8 +1,5 @@ package net.sourceforge.mayfly.util; -import org.apache.commons.collections.IteratorUtils; -import org.apache.commons.lang.ArrayUtils; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -11,8 +8,8 @@ import java.util.List; import java.util.ListIterator; -public class L implements List { - private List delegate; +public class L<T> implements List<T> { + private List<T> delegate; public L() { this(new ArrayList()); @@ -23,10 +20,11 @@ } public L(Iterable items) { - delegate = IteratorUtils.toList(items.iterator()); + this(); + addAll(items); } - public L append(Object o) { + public L append(T o) { add(o); return this; } @@ -36,7 +34,7 @@ } - public ImmutableList asImmutable() { + public ImmutableList<T> asImmutable() { return new ImmutableList(this); } @@ -72,15 +70,15 @@ return delegate.toArray(); } - public Object get(int index) { + public T get(int index) { return delegate.get(index); } - public Object remove(int index) { + public T remove(int index) { return delegate.remove(index); } - public void add(int index, Object element) { + public void add(int index, T element) { delegate.add(index, element); } @@ -92,7 +90,7 @@ return delegate.lastIndexOf(o); } - public boolean add(Object o) { + public boolean add(T o) { return delegate.add(o); } @@ -122,8 +120,8 @@ } /** Iterate through iterable, slurping each element into this list. */ - public L addAll(Iterable iterable) { - Iterator iter = iterable.iterator(); + public L addAll(Iterable<T> iterable) { + Iterator<T> iter = iterable.iterator(); while (iter.hasNext()) { append(iter.next()); } @@ -163,7 +161,7 @@ return delegate.listIterator(index); } - public Object set(int index, Object element) { + public T set(int index, T element) { return delegate.set(index, element); } @@ -176,10 +174,6 @@ return new L(Arrays.asList(objects)); } - public static L fromArray(int[] objects) { - return new L(Arrays.asList(ArrayUtils.toObject(objects))); - } - @Override public String toString() { return delegate.toString(); Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByKeysTest.java 2008-04-07 22:30:07 UTC (rev 553) @@ -12,8 +12,8 @@ public class GroupByKeysTest extends TestCase { public void testResolveColumns() throws Exception { - GroupByKeys keys = new GroupByKeys(); - keys.add(new GroupItem(new Concatenate(new SingleColumn("a"), new QuotedString("'abc'")))); + GroupByKeys keys = new GroupByKeys( + new GroupItem(new Concatenate(new SingleColumn("a"), new QuotedString("'abc'")))); ResultRow row = new ResultRow().withColumn("foo", "a", NullCell.INSTANCE); keys.resolve(row, Evaluator.NO_SUBSELECT_NEEDED); Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByTest.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupByTest.java 2008-04-07 22:30:07 UTC (rev 553) @@ -14,8 +14,7 @@ public class GroupByTest extends TestCase { public void testGroup() throws Exception { - GroupBy groupBy = new GroupBy(); - groupBy.add(new GroupItem(new SingleColumn("a"))); + GroupBy groupBy = new GroupBy(new GroupItem(new SingleColumn("a"))); ResultRows rows = new ResultRows( new ImmutableList() .with(new ResultRow() @@ -59,9 +58,10 @@ } public void testMutiple() throws Exception { - GroupBy groupBy = new GroupBy(); - groupBy.add(new GroupItem(new SingleColumn("a"))); - groupBy.add(new GroupItem(new SingleColumn("b"))); + GroupBy groupBy = new GroupBy( + new GroupItem(new SingleColumn("a")), + new GroupItem(new SingleColumn("b")) + ); ResultRows rows = new ResultRows( new ImmutableList() .with(new ResultRow() Modified: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupedRowsTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupedRowsTest.java 2008-03-29 22:12:03 UTC (rev 552) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/GroupedRowsTest.java 2008-04-07 22:30:07 UTC (rev 553) @@ -120,16 +120,16 @@ } private GroupByKeys keysForColumn(String columnName) { - GroupByKeys keys = new GroupByKeys(); - keys.add(new GroupItem(new SingleColumn(columnName))); - return keys; + return new GroupByKeys( + new GroupItem(new SingleColumn(columnName)) + ); } private GroupByKeys keysForColumns(String columnName1, String columnName2) { - GroupByKeys keys = new GroupByKeys(); - keys.add(new GroupItem(new SingleColumn(columnName1))); - keys.add(new GroupItem(new SingleColumn(columnName2))); - return keys; + return new GroupByKeys( + new GroupItem(new SingleColumn(columnName1)), + new GroupItem(new SingleColumn(columnName2)) + ); } } Added: trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java =================================================================== --- trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java (rev 0) +++ trunk/mayfly/test/net/sourceforge/mayfly/evaluation/select/RowEvaluatorTest.java 2008-04-07 22:30:07 UTC (rev 553) @@ -0,0 +1,56 @@ +package net.sourceforge.mayfly.evaluation.select; + +import net.sourceforge.mayfly.datastore.LongCell; +import net.sourceforge.mayfly.evaluation.NoColumn; +import net.sourceforge.mayfly.evaluation.ResultRow; +import net.sourceforge.mayfly.parser.Location; +import static net.sourceforge.mayfly.util.MayflyAssert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.junit.Test; + + +public class RowEvaluatorTest { + + @Test + public void lookup() { + Evaluator nested = Evaluator.NO_SUBSELECT_NEEDED; + ResultRow correlatedRow = new ResultRow().withColumn("aaa", "a", new LongCell(7)); + RowEvaluator evaluator = new RowEvaluator(correlatedRow, nested); + + ResultRow rowFromInner = new ResultRow().withColumn("bbb", "b", new LongCell(8)); + assertLong(7, evaluator.lookup(rowFromInner, "aaa", "a", Location.UNKNOWN)); + assertLong(7, evaluator.lookup(rowFromInner, null, "a", Location.UNKNOWN)); + assertLong(8, evaluator.lookup(rowFromInner, "bbb", "b", Location.UNKNOWN)); + assertLong(8, evaluator.lookup(rowFromInner, null, "b", Location.UNKNOWN)); + checkLookupFails(rowFromInner, evaluator, null, "c", "c"); + checkLookupFails(rowFromInner, evaluator, "ccc", "c", "ccc.c"); + checkLookupFails(rowFromInner, evaluator, "aaa", "b", "aaa.b"); + checkLookupFails(rowFromInner, evaluator, "bbb", "a", "bbb.a"); + } + + private void checkLookupFails( + ResultRow row, RowEvaluator evaluator, String table, String column, + String expectedDisplayName) { + try { + evaluator.lookup(row, table, column, Location.UNKNOWN); + fail(); + } + catch (NoColumn expected) { + assertEquals(expectedDisplayName, expected.displayName()); + } + } + + @Test + public void lookupName() { + Evaluator nested = Evaluator.NO_SUBSELECT_NEEDED; + ResultRow correlatedRow = new ResultRow().withColumn("aaa", "a", new LongCell(7)); + RowEvaluator evaluator = new RowEvaluator(correlatedRow, nested); + +// assertColumn("aaa", "a", evaluator.lookupName("a")); + assertNull(evaluator.lookupName("c")); + } + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-03-29 22:12:11
|
Revision: 552 http://mayfly.svn.sourceforge.net/mayfly/?rev=552&view=rev Author: kingdon Date: 2008-03-29 15:12:03 -0700 (Sat, 29 Mar 2008) Log Message: ----------- Documentation fixes. Modified Paths: -------------- trunk/mayfly/DESCRIPTION.txt trunk/mayfly/web/index.html Modified: trunk/mayfly/DESCRIPTION.txt =================================================================== --- trunk/mayfly/DESCRIPTION.txt 2008-03-29 21:16:32 UTC (rev 551) +++ trunk/mayfly/DESCRIPTION.txt 2008-03-29 22:12:03 UTC (rev 552) @@ -14,7 +14,7 @@ the same way that one can create Java objects. Mayfly is written in Java (currently works with gcj/libgcj and -Sun Java from 1.4, although exact versions may change), and +Sun Java from 1.5, although exact versions may change), and should run on any OS which provides a Java platform. It relies on the JDBC interfaces from the Java platform (although one has the choice of instantiating a Database object directly if one wishes to avoid @@ -44,8 +44,6 @@ A short list of SQL features which we believe are high priority are: -* subselects - * More SQL operators such as LIKE and BETWEEN. We do not envisage providing network protocols, at least not initially. @@ -58,9 +56,9 @@ and the like. There is a database dumper in the SqlDumper class which dumps to SQL. SQL is a good choice for preserving things like data -types and interchange with other SQL databases. An XML format -might also be interesting for interchange with non-SQL tools -(see class Dumper for an extremely preliminary start at one). +types and interchange with other SQL databases. Other formats, +like XML, YAML (compatible with Rails fixtures), or JSON +might also be interesting for interchange with non-SQL tools. We don't regard Java serialization, XStream, or the like as particularly interesting, as these are closely tied to Mayfly's internal data structures. Modified: trunk/mayfly/web/index.html =================================================================== --- trunk/mayfly/web/index.html 2008-03-29 21:16:32 UTC (rev 551) +++ trunk/mayfly/web/index.html 2008-03-29 22:12:03 UTC (rev 552) @@ -17,7 +17,7 @@ <ul> <li><a href="http://www.apache.org/licenses/LICENSE-2.0" >license</a></li> -<li><a href="http://sourceforge.net/cvs/?group_id=150560" >CVS</a></li> +<li><a href="http://sourceforge.net/svn/?group_id=150560" >sources</a></li> <li><a href="http://sourceforge.net/projects/mayfly/lists" >lists</a></li> <li><a href="http://sourceforge.net/export/rss2_projnews.php?group_id=150560"> <img src="http://images.sourceforge.net/images/xml.png" alt="News feed" width="36" height="14" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ki...@us...> - 2008-03-29 21:16:41
|
Revision: 551 http://mayfly.svn.sourceforge.net/mayfly/?rev=551&view=rev Author: kingdon Date: 2008-03-29 14:16:32 -0700 (Sat, 29 Mar 2008) Log Message: ----------- Remove CVSROOT directory (it was just an artifact of cvs2svn, and removing it after we're in subversion seemed like the easiest way). Removed Paths: ------------- trunk/CVSROOT/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Jim K. <ki...@us...> - 2008-03-28 04:33:44
|
Update of /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv23418/test/net/sourceforge/mayfly/acceptance Modified Files: OrderByTest.java Log Message: Implement the methods in JdbcMetaData relating to null sorting. Index: OrderByTest.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/OrderByTest.java,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** OrderByTest.java 20 Feb 2008 06:55:42 -0000 1.16 --- OrderByTest.java 28 Mar 2008 04:33:39 -0000 1.17 *************** *** 48,57 **** execute("insert into foo (a) values (null)"); execute("insert into foo (a) values ('')"); ! assertResultList( ! dialect.nullSortsLower() ? ! new String[] { " null ", " '' ", " 'one' " } : new String[] { " '' ", " 'one' ", " null " }, ! query("select a from foo order by a") ! ); } --- 48,80 ---- execute("insert into foo (a) values (null)"); execute("insert into foo (a) values ('')"); ! if (dialect.nullSortsLower()) { ! assertTrue(connection.getMetaData().nullsAreSortedLow()); ! assertFalse(connection.getMetaData().nullsAreSortedHigh()); ! assertFalse(connection.getMetaData().nullsAreSortedAtStart()); ! assertFalse(connection.getMetaData().nullsAreSortedAtEnd()); ! assertResultList( ! new String[] { " null ", " '' ", " 'one' " }, ! query("select a from foo order by a") ! ); ! assertResultList( ! new String[] { " 'one' ", " '' ", " null " }, ! query("select a from foo order by a desc") ! ); ! } ! else { ! assertFalse(connection.getMetaData().nullsAreSortedLow()); ! assertTrue(connection.getMetaData().nullsAreSortedHigh()); ! assertFalse(connection.getMetaData().nullsAreSortedAtStart()); ! assertFalse(connection.getMetaData().nullsAreSortedAtEnd()); ! assertResultList( new String[] { " '' ", " 'one' ", " null " }, ! query("select a from foo order by a") ! ); ! assertResultList( ! new String[] { " null ", " 'one' ", " '' " }, ! query("select a from foo order by a desc") ! ); ! ! } } |
From: Jim K. <ki...@us...> - 2008-03-28 04:33:44
|
Update of /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/jdbc In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv23418/src/net/sourceforge/mayfly/jdbc Modified Files: JdbcMetaData.java Log Message: Implement the methods in JdbcMetaData relating to null sorting. Index: JdbcMetaData.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/jdbc/JdbcMetaData.java,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** JdbcMetaData.java 25 Mar 2008 05:29:00 -0000 1.6 --- JdbcMetaData.java 28 Mar 2008 04:33:39 -0000 1.7 *************** *** 341,357 **** public boolean nullsAreSortedAtEnd() throws SQLException { ! throw new UnimplementedException(); } public boolean nullsAreSortedAtStart() throws SQLException { ! throw new UnimplementedException(); } public boolean nullsAreSortedHigh() throws SQLException { ! throw new UnimplementedException(); } public boolean nullsAreSortedLow() throws SQLException { ! throw new UnimplementedException(); } --- 341,357 ---- public boolean nullsAreSortedAtEnd() throws SQLException { ! return false; } public boolean nullsAreSortedAtStart() throws SQLException { ! return false; } public boolean nullsAreSortedHigh() throws SQLException { ! return false; } public boolean nullsAreSortedLow() throws SQLException { ! return true; } |
From: Jim K. <ki...@us...> - 2008-03-25 05:29:06
|
Update of /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/jdbc In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv862/src/net/sourceforge/mayfly/jdbc Modified Files: JdbcMetaData.java Log Message: Define various meta data methods which Hibernate wants. As these are mostly versions and names and such, I'm not sure adding tests is particularly interesting, although for at least some it could be potentially fruitful. Index: JdbcMetaData.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/jdbc/JdbcMetaData.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** JdbcMetaData.java 15 Oct 2007 18:59:35 -0000 1.5 --- JdbcMetaData.java 25 Mar 2008 05:29:00 -0000 1.6 *************** *** 26,34 **** public boolean dataDefinitionCausesTransactionCommit() throws SQLException { ! throw new UnimplementedException(); } public boolean dataDefinitionIgnoredInTransactions() throws SQLException { ! throw new UnimplementedException(); } --- 26,34 ---- public boolean dataDefinitionCausesTransactionCommit() throws SQLException { ! return false; } public boolean dataDefinitionIgnoredInTransactions() throws SQLException { ! return false; } *************** *** 81,89 **** public int getDatabaseMajorVersion() throws SQLException { ! throw new UnimplementedException(); } public int getDatabaseMinorVersion() throws SQLException { ! throw new UnimplementedException(); } --- 81,89 ---- public int getDatabaseMajorVersion() throws SQLException { ! return 0; } public int getDatabaseMinorVersion() throws SQLException { ! return 0; } *************** *** 93,97 **** public String getDatabaseProductVersion() throws SQLException { ! throw new UnimplementedException(); } --- 93,97 ---- public String getDatabaseProductVersion() throws SQLException { ! return ""; } *************** *** 101,117 **** public int getDriverMajorVersion() { ! throw new UnimplementedException(); } public int getDriverMinorVersion() { ! throw new UnimplementedException(); } public String getDriverName() throws SQLException { ! throw new UnimplementedException(); } public String getDriverVersion() throws SQLException { ! throw new UnimplementedException(); } --- 101,117 ---- public int getDriverMajorVersion() { ! return 0; } public int getDriverMinorVersion() { ! return 0; } public String getDriverName() throws SQLException { ! return "Mayfly JDBC Driver"; } public String getDriverVersion() throws SQLException { ! return ""; } |
From: Jim K. <ki...@us...> - 2008-03-25 05:03:18
|
Update of /cvsroot/mayfly/mayfly/test/lib In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22151/test/lib Added Files: junit-4.4.jar Removed Files: junit.jar Log Message: Update junit jar to 4.4 (not yet using any of the new features, though). --- junit.jar DELETED --- --- NEW FILE: junit-4.4.jar --- (This appears to be a binary file; contents omitted.) |
From: Jim K. <ki...@us...> - 2008-03-25 05:03:18
|
Update of /cvsroot/mayfly/mayfly In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22151 Modified Files: .classpath Log Message: Update junit jar to 4.4 (not yet using any of the new features, though). Index: .classpath =================================================================== RCS file: /cvsroot/mayfly/mayfly/.classpath,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -d -r1.22 -r1.23 *** .classpath 12 Mar 2008 02:42:34 -0000 1.22 --- .classpath 25 Mar 2008 05:03:14 -0000 1.23 *************** *** 7,13 **** <classpathentry kind="lib" path="src/lib/commons-collections-3.1.jar" sourcepath="src/lib-src/commons-collections-3.1-src.zip"/> <classpathentry kind="lib" path="src/lib/commons-lang-2.1.jar" sourcepath="src/lib-src/commons-lang-2.1-src.zip"/> - <classpathentry kind="lib" path="test/lib/junit.jar"/> <classpathentry kind="lib" path="test/lib/mysql-connector-java-3.1.12-bin.jar"/> - <classpathentry kind="lib" path="test/lib/junit-addons-1.4.jar" sourcepath="test/lib-src/junit-addons-1.4-src.jar"/> <classpathentry kind="lib" path="test/lib/postgresql-8.1-404.jdbc3.jar"/> <classpathentry kind="lib" path="test/lib/derby-10.1.2.1.jar" sourcepath="test/lib-src/db-derby-10.1.2.1-src.zip"/> --- 7,11 ---- *************** *** 16,19 **** --- 14,19 ---- <classpathentry kind="lib" path="test/lib/smallsql-0.15.jar"/> <classpathentry kind="lib" path="test/lib/hsqldb-1.8.0.7.jar" sourcepath="test/lib-src/hsqldb_1_8_0_7.zip"/> + <classpathentry kind="lib" path="test/lib/junit-4.4.jar"/> + <classpathentry kind="lib" path="test/lib/junit-addons-1.4.jar"/> <classpathentry kind="output" path="bin"/> </classpath> |
From: Jim K. <ki...@us...> - 2008-03-17 05:24:11
|
Update of /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22466/test/net/sourceforge/mayfly/acceptance Modified Files: DataDefinitionTest.java DerbyDialect.java Dialect.java DropUniqueConstraintTest.java HypersonicDialect.java IndexTest.java MayflyDialect.java PostgresDialect.java SqlTestCase.java ValueTest.java Log Message: * Add test for DROP INDEX on a constraint (MySQL-specific). * Use generics a few more places in the Mayfly code. * Index names are now unique across all tables - this makes Mayfly compatible with most databases (while not losing MySQL compatibility). Index: DataDefinitionTest.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/DataDefinitionTest.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** DataDefinitionTest.java 23 Jul 2007 20:09:00 -0000 1.7 --- DataDefinitionTest.java 17 Mar 2008 05:24:07 -0000 1.8 *************** *** 22,26 **** // In our book, "data definition" includes "data undefinition". ! // So DROP TABLE tests belong in this class. // Maybe there's a motto here: --- 22,26 ---- // In our book, "data definition" includes "data undefinition". ! // So that's what DROP TABLE tests are doing here. // Maybe there's a motto here: *************** *** 60,62 **** --- 60,68 ---- } + public void testDroppingTableDropsIndexes() throws Exception { + execute("create table foo(x integer not null)"); + execute("create index x_index on foo(x)"); + execute("drop table foo"); + } + } Index: SqlTestCase.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/SqlTestCase.java,v retrieving revision 1.26 retrieving revision 1.27 diff -C2 -d -r1.26 -r1.27 *** SqlTestCase.java 7 Nov 2007 14:32:01 -0000 1.26 --- SqlTestCase.java 17 Mar 2008 05:24:07 -0000 1.27 *************** *** 236,238 **** --- 236,251 ---- } + protected void dropIndex(String name, String table) throws SQLException { + execute(dropIndexCommand(name, table)); + } + + protected String dropIndexCommand(String name, String table) { + if (dialect.indexNamesArePerTable()) { + return "drop index " + name + " on " + table; + } + else { + return "drop index " + name; + } + } + } Index: ValueTest.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/ValueTest.java,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** ValueTest.java 7 Feb 2008 22:14:02 -0000 1.21 --- ValueTest.java 17 Mar 2008 05:24:07 -0000 1.22 *************** *** 6,10 **** /** * @internal ! * See {@link ValueTest} for insert cases involving subselects */ public class ValueTest extends SqlTestCase { --- 6,10 ---- /** * @internal ! * See {@link InsertSubselectTest} for insert cases involving subselects */ public class ValueTest extends SqlTestCase { Index: HypersonicDialect.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/HypersonicDialect.java,v retrieving revision 1.52 retrieving revision 1.53 diff -C2 -d -r1.52 -r1.53 *** HypersonicDialect.java 2 Mar 2008 08:23:19 -0000 1.52 --- HypersonicDialect.java 17 Mar 2008 05:24:07 -0000 1.53 *************** *** 333,336 **** --- 333,341 ---- return "HSQL Database Engine"; } + + @Override + public boolean canDropIndexGivingWrongTable() { + return true; + } } Index: Dialect.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/Dialect.java,v retrieving revision 1.100 retrieving revision 1.101 diff -C2 -d -r1.100 -r1.101 *** Dialect.java 2 Mar 2008 08:23:19 -0000 1.100 --- Dialect.java 17 Mar 2008 05:24:07 -0000 1.101 *************** *** 802,805 **** --- 802,813 ---- } + public boolean haveDropIndexOn() { + return true; + } + + public boolean canDropIndexGivingWrongTable() { + return false; + } + public boolean canIndexPartOfColumn() { return false; Index: MayflyDialect.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/MayflyDialect.java,v retrieving revision 1.48 retrieving revision 1.49 diff -C2 -d -r1.48 -r1.49 *** MayflyDialect.java 22 Feb 2008 17:19:24 -0000 1.48 --- MayflyDialect.java 17 Mar 2008 05:24:07 -0000 1.49 *************** *** 185,194 **** the production database (say, Postgres). We might end up reversing this decision, ! or introducing the concept of options ! (say, Database#options() and JdbcDriver#options(String url) ! methods which return an Options object in which ! one can set options. Or perhaps we only allow ! the options to be passed in when the Database is ! created). */ return true; --- 185,189 ---- the production database (say, Postgres). We might end up reversing this decision, ! or mking it something to set in Options. */ return true; *************** *** 252,264 **** @Override - public boolean indexNamesArePerTable() { - /* Actually, we want this to be false but also accept the - * syntax DROP INDEX index_name ON table_name - * (which is just like DROP INDEX index_name but it complains - * if that index is from a different table). */ - return !wishThisWereTrue(); - } - - @Override public boolean haveAddColumnAfter() { return true; --- 247,250 ---- Index: DerbyDialect.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/DerbyDialect.java,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -d -r1.35 -r1.36 *** DerbyDialect.java 13 Nov 2007 15:44:22 -0000 1.35 --- DerbyDialect.java 17 Mar 2008 05:24:07 -0000 1.36 *************** *** 314,317 **** --- 314,322 ---- return false; } + + @Override + public boolean haveDropIndexOn() { + return false; + } } Index: IndexTest.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/IndexTest.java,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** IndexTest.java 15 Mar 2008 03:10:13 -0000 1.9 --- IndexTest.java 17 Mar 2008 05:24:07 -0000 1.10 *************** *** 1,5 **** package net.sourceforge.mayfly.acceptance; - import java.sql.SQLException; public class IndexTest extends SqlTestCase { --- 1,4 ---- *************** *** 81,85 **** else { expectExecuteFailure(duplicate, ! "index an_index_name already exists"); } } --- 80,97 ---- else { expectExecuteFailure(duplicate, ! "table foo already has an index an_index_name"); ! } ! } ! ! public void testIndexNamesAreCaseInsensitive() throws Exception { ! execute("create table foo(a integer, b integer)"); ! execute("create index an_index_name on foo(a)"); ! String duplicate = "create index an_iNdEx_name on foo(b)"; ! if (false) { ! execute(duplicate); ! } ! else { ! expectExecuteFailure(duplicate, ! "table foo already has an index an_iNdEx_name"); } } *************** *** 101,105 **** String tryToCreateIndexWithSameName = "create index an_index on foo(b)"; expectExecuteFailure(tryToCreateIndexWithSameName, ! "duplicate index an_index"); String dropWithoutGivingTable = "drop index an_index"; --- 113,117 ---- String tryToCreateIndexWithSameName = "create index an_index on foo(b)"; expectExecuteFailure(tryToCreateIndexWithSameName, ! "table foo already has an index an_index"); String dropWithoutGivingTable = "drop index an_index"; *************** *** 116,123 **** } public void testDroppingUniqueIndexDropsConstraint() throws Exception { execute("create table foo(a integer, b varchar(20))"); execute("create unique index an_index on foo(a)"); ! dropIndex("an_index"); dialect.checkDump( "CREATE TABLE foo(\n" + --- 128,180 ---- } + public void testDropIndexBadName() throws Exception { + execute("create table foo(a integer)"); + expectExecuteFailure( + dropIndexCommand("no_such", "foo"), + "no index no_such" + ); + } + + public void testDropIndexWithWrongTable() throws Exception { + execute("create table foo(a integer, b integer)"); + execute("create table bar(a integer)"); + execute("create index an_index on foo(a)"); + String dropIndexOn = "drop index an_index on bar"; + if (dialect.canDropIndexGivingWrongTable()) { + execute(dropIndexOn); + + // check it is really gone + execute("create index an_index on foo(b)"); + } + else { + /* Could be syntax error, or something like "no index an_index", + or the Mayfly expectation of telling exactly what is happening. + */ + expectExecuteFailure(dropIndexOn, + "attempt to drop index an_index from table bar " + + "although the index is on table foo"); + } + } + + public void testDropIndexWithCorrectTable() throws Exception { + execute("create table foo(a integer, b integer)"); + execute("create table bar(a integer)"); + execute("create index an_index on foo(a)"); + String dropIndexOn = "drop index an_index on foo"; + if (dialect.haveDropIndexOn()) { + execute(dropIndexOn); + + // Check that it is really gone + execute("create index an_index on foo(b)"); + } + else { + expectExecuteFailure(dropIndexOn, "expected end of file but got ON"); + } + } + public void testDroppingUniqueIndexDropsConstraint() throws Exception { execute("create table foo(a integer, b varchar(20))"); execute("create unique index an_index on foo(a)"); ! dropIndex("an_index", "foo"); dialect.checkDump( "CREATE TABLE foo(\n" + *************** *** 143,147 **** execute("create index an_index on foo(a)"); ! dropIndex("an_index"); dialect.checkDump( "CREATE TABLE foo(\n" + --- 200,204 ---- execute("create index an_index on foo(a)"); ! dropIndex("an_index", "foo"); dialect.checkDump( "CREATE TABLE foo(\n" + *************** *** 155,167 **** } - private void dropIndex(String name) throws SQLException { - if (dialect.indexNamesArePerTable()) { - execute("drop index " + name + " on foo"); - } - else { - execute("drop index " + name); - } - } - public void mysql_only_testAlterTableDropIndex() throws Exception { // another syntax, as an alternative to the DROP INDEX one --- 212,215 ---- Index: PostgresDialect.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/PostgresDialect.java,v retrieving revision 1.42 retrieving revision 1.43 diff -C2 -d -r1.42 -r1.43 *** PostgresDialect.java 16 Feb 2008 19:46:51 -0000 1.42 --- PostgresDialect.java 17 Mar 2008 05:24:07 -0000 1.43 *************** *** 332,334 **** --- 332,339 ---- } + @Override + public boolean haveDropIndexOn() { + return false; + } + } Index: DropUniqueConstraintTest.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/acceptance/DropUniqueConstraintTest.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** DropUniqueConstraintTest.java 18 Dec 2007 21:21:12 -0000 1.1 --- DropUniqueConstraintTest.java 17 Mar 2008 05:24:07 -0000 1.2 *************** *** 27,30 **** --- 27,56 ---- } } + + public void testDropIndex() throws Exception { + /* MySQL takes the index/constraint unification to new heights; + the way to drop a constraint is DROP INDEX, even if there + was no CREATE INDEX. + */ + execute("create table foo(" + + "x integer not null, " + + "y varchar(80), " + + "constraint x_uniq unique(x)" + + ")"); + + execute("insert into foo(x, y) values(5, 'first')"); + String insertSecond = "insert into foo(x, y) values(5, 'second')"; + expectExecuteFailure(insertSecond, + "unique constraint in table foo, column x: duplicate value 5"); + + String sql = dropIndexCommand("x_uniq", "foo"); + if (dialect.haveDropConstraint()) { + expectExecuteFailure(sql, "no index x_uniq"); + } + else { + execute(sql); + execute(insertSecond); + } + } } |
From: Jim K. <ki...@us...> - 2008-03-17 05:24:10
|
Update of /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22466/test/net/sourceforge/mayfly Modified Files: TableNamesCaseSensitiveTest.java Log Message: * Add test for DROP INDEX on a constraint (MySQL-specific). * Use generics a few more places in the Mayfly code. * Index names are now unique across all tables - this makes Mayfly compatible with most databases (while not losing MySQL compatibility). Index: TableNamesCaseSensitiveTest.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/test/net/sourceforge/mayfly/TableNamesCaseSensitiveTest.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** TableNamesCaseSensitiveTest.java 7 Nov 2007 23:46:47 -0000 1.7 --- TableNamesCaseSensitiveTest.java 17 Mar 2008 05:24:07 -0000 1.8 *************** *** 138,141 **** --- 138,156 ---- } + public void testCreateIndex() throws Exception { + database.execute("create table foo(a integer)"); + expectExecuteFailure("create index an_index on FOO(a)", + "attempt to refer to table foo as FOO " + + "(with case sensitive table names enabled)"); + } + + public void testDropIndex() throws Exception { + database.execute("create table foo(a integer)"); + database.execute("create index an_index on foo(a)"); + expectExecuteFailure("drop index an_index on FOO", + "attempt to refer to table foo as FOO " + + "(with case sensitive table names enabled)"); + } + private void expectQueryFailure(String sql, String message) { try { |
From: Jim K. <ki...@us...> - 2008-03-17 05:24:10
|
Update of /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/parser In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22466/src/net/sourceforge/mayfly/parser Modified Files: Parser.java Log Message: * Add test for DROP INDEX on a constraint (MySQL-specific). * Use generics a few more places in the Mayfly code. * Index names are now unique across all tables - this makes Mayfly compatible with most databases (while not losing MySQL compatibility). Index: Parser.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/parser/Parser.java,v retrieving revision 1.123 retrieving revision 1.124 diff -C2 -d -r1.123 -r1.124 *** Parser.java 22 Feb 2008 17:19:24 -0000 1.123 --- Parser.java 17 Mar 2008 05:24:06 -0000 1.124 *************** *** 1,10 **** package net.sourceforge.mayfly.parser; - import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_values; import static net.sourceforge.mayfly.parser.TokenType.EQUAL; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_column; import static net.sourceforge.mayfly.parser.TokenType.IDENTIFIER; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_character; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_set; import static net.sourceforge.mayfly.parser.TokenType.CLOSE_PAREN; --- 1,11 ---- package net.sourceforge.mayfly.parser; import static net.sourceforge.mayfly.parser.TokenType.EQUAL; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_column; import static net.sourceforge.mayfly.parser.TokenType.IDENTIFIER; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_character; + import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_on; import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_set; + import static net.sourceforge.mayfly.parser.TokenType.KEYWORD_values; import static net.sourceforge.mayfly.parser.TokenType.CLOSE_PAREN; *************** *** 488,494 **** private Command parseDropIndex() { String indexName = consumeIdentifier(); ! expectAndConsume(TokenType.KEYWORD_on); ! UnresolvedTableReference table = parseTableReference(); ! return new DropIndex(table, indexName); } --- 489,499 ---- private Command parseDropIndex() { String indexName = consumeIdentifier(); ! if (consumeIfMatches(KEYWORD_on)) { ! UnresolvedTableReference table = parseTableReference(); ! return new DropIndex(table, indexName); ! } ! else { ! return new DropIndex(null, indexName); ! } } |
From: Jim K. <ki...@us...> - 2008-03-17 05:24:10
|
Update of /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/datastore In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22466/src/net/sourceforge/mayfly/datastore Modified Files: DataStore.java Indexes.java Schema.java Log Message: * Add test for DROP INDEX on a constraint (MySQL-specific). * Use generics a few more places in the Mayfly code. * Index names are now unique across all tables - this makes Mayfly compatible with most databases (while not losing MySQL compatibility). Index: DataStore.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/datastore/DataStore.java,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** DataStore.java 5 Jan 2008 19:56:41 -0000 1.36 --- DataStore.java 17 Mar 2008 05:24:06 -0000 1.37 *************** *** 274,276 **** --- 274,284 ---- } + public DataStore dropIndex(String schema, String indexName) { + Schema existing = schema(schema); + return replace( + schema, + existing.dropIndex(indexName) + ); + } + } Index: Indexes.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/datastore/Indexes.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Indexes.java 15 Mar 2008 03:10:11 -0000 1.3 --- Indexes.java 17 Mar 2008 05:24:06 -0000 1.4 *************** *** 81,83 **** --- 81,92 ---- } + public boolean hasIndex(String indexName) { + for (Index index : indexes) { + if (indexName.equalsIgnoreCase(index.name())) { + return true; + } + } + return false; + } + } Index: Schema.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/datastore/Schema.java,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -d -r1.35 -r1.36 *** Schema.java 5 Jan 2008 19:56:41 -0000 1.35 --- Schema.java 17 Mar 2008 05:24:06 -0000 1.36 *************** *** 16,24 **** import java.util.Iterator; import java.util.List; import java.util.Set; public class Schema { ! private final ImmutableMap tables; public Schema() { --- 16,25 ---- import java.util.Iterator; import java.util.List; + import java.util.Map; import java.util.Set; public class Schema { ! private final ImmutableMap<String, TableData> tables; public Schema() { *************** *** 26,30 **** } ! private Schema(ImmutableMap tables) { this.tables = tables; } --- 27,31 ---- } ! private Schema(ImmutableMap<String, TableData> tables) { this.tables = tables; } *************** *** 100,104 **** String canonicalTableName = lookUpTable(table); ! return (TableData) tables.get(canonicalTableName); } --- 101,105 ---- String canonicalTableName = lookUpTable(table); ! return tables.get(canonicalTableName); } *************** *** 112,117 **** public String lookUpTable(String target, Location location, Options options) { ! for (Iterator iter = tables.keySet().iterator(); iter.hasNext(); ) { ! String canonicalTable = (String) iter.next(); if (canonicalTable.equalsIgnoreCase(target)) { if (options.tableNamesCaseSensitive() --- 113,117 ---- public String lookUpTable(String target, Location location, Options options) { ! for (String canonicalTable : tables.keySet()) { if (canonicalTable.equalsIgnoreCase(target)) { if (options.tableNamesCaseSensitive() *************** *** 136,141 **** private String lookUpTableOrNull(String target, Options options) { ! for (Iterator iter = tables.keySet().iterator(); iter.hasNext(); ) { ! String canonicalTable = (String) iter.next(); if (options.tableNamesEqual(canonicalTable, target)) { return canonicalTable; --- 136,140 ---- private String lookUpTableOrNull(String target, Options options) { ! for (String canonicalTable : tables.keySet()) { if (options.tableNamesEqual(canonicalTable, target)) { return canonicalTable; *************** *** 216,221 **** public void checkDropTable(DataStore store, String schema, String table) { ! for (Iterator iter = tables.values().iterator(); iter.hasNext();) { ! TableData potentialReferencer = (TableData) iter.next(); potentialReferencer.checkDropTable(store, schema, table); } --- 215,219 ---- public void checkDropTable(DataStore store, String schema, String table) { ! for (TableData potentialReferencer : tables.values()) { potentialReferencer.checkDropTable(store, schema, table); } *************** *** 235,244 **** --- 233,277 ---- public Schema addIndex(String table, Index index) { + String foundTable = findTableForIndex(index.name()); + if (foundTable != null) { + throw new MayflyException( + "table " + foundTable + + " already has an index " + index.name()); + } return replaceTable(table, table(table).addIndex(index)); } public Schema dropIndex(String table, String indexName) { + if (table == null) { + throw new NullPointerException("table expected"); + } + + String foundTable = findTableForIndex(indexName); + if (table.equalsIgnoreCase(foundTable)) { + return replaceTable(table, table(table).dropIndex(indexName)); + } + else { + throw new MayflyException( + "attempt to drop index " + indexName + " from table " + + table + " although the index is on table " + foundTable); + } + } + + public Schema dropIndex(String indexName) { + String table = findTableForIndex(indexName); + if (table == null) { + throw new MayflyException("no index " + indexName); + } return replaceTable(table, table(table).dropIndex(indexName)); } + public String findTableForIndex(String indexName) { + for (Map.Entry<String, TableData> entry : tables.entrySet()) { + if (entry.getValue().indexes.hasIndex(indexName)) { + return entry.getKey(); + } + } + return null; + } + } |
From: Jim K. <ki...@us...> - 2008-03-17 05:24:10
|
Update of /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/evaluation/command In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22466/src/net/sourceforge/mayfly/evaluation/command Modified Files: DropIndex.java Log Message: * Add test for DROP INDEX on a constraint (MySQL-specific). * Use generics a few more places in the Mayfly code. * Index names are now unique across all tables - this makes Mayfly compatible with most databases (while not losing MySQL compatibility). Index: DropIndex.java =================================================================== RCS file: /cvsroot/mayfly/mayfly/src/net/sourceforge/mayfly/evaluation/command/DropIndex.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** DropIndex.java 29 Nov 2007 23:45:18 -0000 1.1 --- DropIndex.java 17 Mar 2008 05:24:06 -0000 1.2 *************** *** 16,22 **** @Override public UpdateStore update(DataStore store, String currentSchema) { ! TableReference reference = table.resolve(store, currentSchema, null); ! DataStore newStore = store.dropIndex(reference, this.indexName); ! return new UpdateStore(newStore, 0); } --- 16,28 ---- @Override public UpdateStore update(DataStore store, String currentSchema) { ! if (table == null) { ! DataStore newStore = store.dropIndex(currentSchema, this.indexName); ! return new UpdateStore(newStore, 0); ! } ! else { ! TableReference reference = table.resolve(store, currentSchema, null); ! DataStore newStore = store.dropIndex(reference, this.indexName); ! return new UpdateStore(newStore, 0); ! } } |