/* // $Id: //guest/julian_hyde/saffron/src/main/saffron/rel/ExtenderAggregation.java#1 $ // Saffron preprocessor and data engine // Copyright (C) 2002 Julian Hyde <julian.hyde@mail.com> // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // See the COPYING file located in the top-level-directory of // the archive of this library for complete text of license. */ package saffron.rel; import openjava.mop.Environment; import openjava.mop.OJClass; import openjava.mop.OJMethod; import openjava.mop.Toolbox; import openjava.ptree.*; import saffron.AggregatorExtender; import saffron.opt.Implementor; import saffron.util.Util; /** * <code>ExtenderAggregation</code> is an aggregator which works by * instantiating a user-defined aggregator ({@link AggregatorExtender}), as * opposed to generating custom code. * * <p> Two bugs with the current implementation of {@link #implementStart} * etc. First, the aggregator expression should be evaluated only once -- when * the query starts -- and stored in a variable. I guess it should be added to * the environment holding the query. * * <p> Second, we pass real expressions as the values of the dummy arguments to * {@link #implementStart} and {@link #implementResult}. This is inefficient, * but moreover, it is conceivable that the expressions will not be valid in * the scope where start and result are executed. * * @author jhyde * @since 3 February, 2002 * @version $Id: //guest/julian_hyde/saffron/src/main/saffron/rel/ExtenderAggregation.java#1 $ **/ public class ExtenderAggregation implements Aggregation { // AggregatorExtender ext; Expression aggExp; OJClass aggClazz; OJClass[] argTypes; Variable var; OJMethod startMethod; OJMethod nextMethod; OJMethod mergeMethod; OJMethod resultMethod; ExtenderAggregation(Expression aggExp, Environment env, OJClass[] argTypes) { this.aggExp = aggExp; this.aggClazz = Toolbox.getType(env, aggExp); Util.assert( OJClass.forClass(AggregatorExtender.class).isAssignableFrom( aggClazz)); this.argTypes = argTypes; this.startMethod = findMethod(aggClazz, "start", argTypes, 0, true); this.nextMethod = findMethod(aggClazz, "next", argTypes, 1, true); this.mergeMethod = findMethod(aggClazz, "merge", argTypes, 2, false); this.resultMethod = findMethod(aggClazz, "result", argTypes, 1, true); } /** * Returns whether this aggregator has an overloading which matches the * given name and argument types. **/ public static boolean matches(OJClass aggClazz, OJClass[] argTypes) { return findMethod(aggClazz, "result", argTypes, 1, false) != null; } private static OJMethod findMethod( OJClass aggClazz, String name, OJClass[] argTypes, int extra, boolean fail) { if (extra > 0) { OJClass[] newArgTypes = new OJClass[argTypes.length + extra]; System.arraycopy(argTypes, 0, newArgTypes, 0, argTypes.length); while (extra > 0) { newArgTypes[argTypes.length - extra--] = Toolbox.clazzObject; } argTypes = newArgTypes; } OJMethod[] allMethods = aggClazz.getMethods(); loop: for (int i = 0, n = allMethods.length; i < n; i++) { OJMethod method = allMethods[i]; if (method.getName().equals(name) && method.getParameterTypes().length == argTypes.length) { OJClass[] parameterTypes = method.getParameterTypes(); for (int j = 0; j < argTypes.length; j++) { if (argTypes[j] != parameterTypes[j]) { continue loop; } } return method; } } if (fail) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < argTypes.length; i++) { if (i > 0) { sb.append(", "); } sb.append(argTypes[i]); } throw Util.newInternal( "could not find method " + name + "(" + sb + ") required to implement AggregatorExtender"); } else { return null; } } // implement Aggregation public OJClass getReturnType() { return resultMethod.getReturnType(); } // implement Aggregation public OJClass[] getParameterTypes() { return argTypes; } // implement Aggregation public boolean canMerge() { return mergeMethod != null; } // implement Aggregation public Expression implementStart( Implementor implementor, Rel rel, int[] args) { this.var = implementor.newVariable(); StatementList stmtList = implementor.getStatementList(); // Nth agg = new Nth(5); stmtList.add( new VariableDeclaration( TypeName.forOJClass(aggClazz), var.toString(), aggExp)); // "agg.start((T0) 0, (T1) null)" ExpressionList exprList = new ExpressionList(); for (int i = 0; i < argTypes.length; i++) { exprList.add( new CastExpression( TypeName.forOJClass(argTypes[i]), argTypes[i].isPrimitive() ? Literal.constantZero() : Literal.constantNull())); } return new MethodCall( var, "start", exprList); } // implement Aggregation public void implementNext( Implementor implementor, Rel rel, Expression accumulator, int[] args) { // "agg = agg.next(arg..., acc);" StatementList stmtList = implementor.getStatementList(); ExpressionList exprList = new ExpressionList(); for (int i = 0; i < args.length; i++) { exprList.add( implementor.translateInputField(rel, 0, args[i])); } exprList.add(accumulator); stmtList.add( new ExpressionStatement( new AssignmentExpression( var, AssignmentExpression.EQUALS, new MethodCall( var, "next", exprList)))); } // implement Aggregation public void implementMerge( Implementor implementor, Rel rel, Expression accumulator, Expression otherAccumulator) { Util.assert(canMerge()); // "agg = agg.merge((T0) 0, (T1) null..., acc, otherAcc)" StatementList stmtList = implementor.getStatementList(); ExpressionList exprList = new ExpressionList(); for (int i = 0; i < argTypes.length; i++) { exprList.add( new CastExpression( TypeName.forOJClass(argTypes[i]), argTypes[i].isPrimitive() ? Literal.constantZero() : Literal.constantNull())); } exprList.add(accumulator); exprList.add(otherAccumulator); stmtList.add( new ExpressionStatement( new AssignmentExpression( var, AssignmentExpression.EQUALS, new MethodCall( var, "merge", exprList)))); } // implement Aggregation public Expression implementResult(Expression accumulator) { // "agg.result((T0) 0, (T1) null..., acc)" ExpressionList exprList = new ExpressionList(); for (int i = 0; i < argTypes.length; i++) { exprList.add( new CastExpression( TypeName.forOJClass(argTypes[i]), argTypes[i].isPrimitive() ? Literal.constantZero() : Literal.constantNull())); } exprList.add(accumulator); return new MethodCall( var, "result", exprList); } } // End ExtenderAggregation.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 1474 | Julian Hyde |
saffron: Aggregations are working. Renamed 'aggregator' to 'aggregation'. |
||
#1 | 1467 | Julian Hyde |
saffron: First saffron check-in; incorporate my changes to openjava. |