/* // $Id: //guest/julian_hyde/saffron/src/main/saffron/rel/Rel.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.ptree.Expression; import openjava.ptree.Variable; import openjava.ptree.util.EvaluationShuttle; import openjava.tools.DebugOut; import saffron.PlanWriter; import saffron.Planner; import saffron.opt.*; import saffron.runtime.Plan; import saffron.util.RelEnvironment; import saffron.util.RelVisitor; import saffron.util.Util; import java.io.PrintWriter; import java.io.StringWriter; /** * A <code>Rel</code> is a relational expression. It is NOT an {@link * openjava.ptree.Expression}. **/ public abstract class Rel { /** unique id of this object -- for debugging **/ protected int id; /** generator for {@link #id} values **/ static int nextId = 0; /** cached type of this relational expression */ OJClass rowType; private RelEnvironment env; protected Cluster cluster; /** The variable by which to refer to rows from this relational expression, * as correlating expressions; null if this expression is not correlated * on. **/ private String corelVariable; static final Rel[] emptyArray = new Rel[0]; static final Expression[] emptyExpressionArray = new Expression[0]; /** * Creates a <code>Rel</code>. */ public Rel(Cluster cluster) { super(); this.cluster = cluster; this.env = new RelEnvironment(cluster.env, this); this.id = nextId++; DebugOut.println("new " + getClass().getName() + ": id=" + id); } // override Object (public, does not throw CloneNotSupportedException) public abstract Object clone(); public int getId() { return id; } public Environment getParentEnv() { return env.getParent(); } public RelEnvironment getEnvironment() { return env; } public Query getQuery() { return cluster.query; } public Cluster getCluster() { return cluster; } /** * Returns the type of an expression in this <code>Rel</code>'s * environment. */ public OJClass getType(Expression exp) { try { return exp.getType(env); } catch (Exception e) { throw Util.newInternal(e); } } /** * Returns the type of the rows returned by this relational expression. */ public final OJClass getRowType() { if (rowType == null) { rowType = deriveRowType(); } return rowType; } /** * Returns the current class. Generally, this method is called to find a * suitable a holder for temporary classes. */ public final OJClass getTempClass() { String className = env.currentClassName(); return env.lookupClass(className); } /** * Returns an array of this <code>Rel</code>'s inputs. If there are no * inputs, returns an empty array, not <code>null</code>. */ public Rel[] getInputs() { return emptyArray; } /** * Replaces the <code>ordinalInParent</code><sup>th</sup> input. You must * override this method if you override {@link #getInputs}. */ public void replaceInput(int ordinalInParent, Rel p) { throw Util.newInternal( "replaceInput called on " + this); } /** * Returns an array of this <code>Rel</code>'s child expressions (not * including the inputs returned by {@link #getInputs}. If there are no * child expressions, returns an empty array, not <code>null</code>. */ public Expression[] getChildExps() { return emptyExpressionArray; } public void explain(PlanWriter pw) { pw.explain(this, null); } /** * Returns the name of this <code>Rel</code>'s class, sans package name, * for use in {@link #explain}. For example, for a * <code>saffron.ArrayRel.ArrayReader</code>, returns "ArrayReader". **/ public final String getRelTypeName() { String className = getClass().getName(); int i = className.lastIndexOf("$"); if (i >= 0) { return className.substring(i + 1); } i = className.lastIndexOf("."); if (i >= 0) { return className.substring(i + 1); } return className; } /* // implement ParseTree public boolean equals(ParseTree p) { throw new UnsupportedOperationException(); } // implement ParseTree public void replace(ParseTree p) { throw new UnsupportedOperationException(); } // implement ParseTree public ParseTree makeRecursiveCopy() { throw new UnsupportedOperationException(); } // implement ParseTree public ParseTree makeCopy() { throw new UnsupportedOperationException(); } // implement ParseTree public boolean eq(ParseTree p) { throw new UnsupportedOperationException(); } */ public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); boolean brief = true; PlanWriter planWriter = new PlanWriter(pw, brief); explain(planWriter); planWriter.close(); return sw.toString(); } /* // implement ParseTree public void writeCode() { throw new UnsupportedOperationException(); } // implement ParseTree public String toFlattenString() { throw new UnsupportedOperationException(); } // implement ParseTree public int getObjectID() { throw new UnsupportedOperationException(); } */ // public void accept(RelVisitor v) // { // v.visit(this); // } public void childrenAccept(RelVisitor visitor) { Rel[] inputs = getInputs(); for (int i = 0; i < inputs.length; i++) { visitor.visit(inputs[i], i, this); } // Expression[] children = getChildExps(); // for (int i = 0; i < children.length; i++) { // visitor.visit(children[i]); // } } protected abstract OJClass deriveRowType(); /** * Get the <code>i</code><sup>th</sup> input. */ public Rel getInput(int i) { Rel[] inputs = getInputs(); return inputs[i]; } /** * Returns a variable with which to reference the current row of this * relational expression as a correlating variable. Creates a variable if * none exists. **/ public String getOrCreateCorelVariable() { if (corelVariable == null) { corelVariable = getQuery().createCorel(this); } return corelVariable; } public String getCorelVariable() { return corelVariable; } public void setCorelVariable(String corelVariable) { this.corelVariable = corelVariable; } /** * Changes the convention of a relation. This method is called by {@link * saffron.Converter.ConverterRule#apply}, so it must NOT add a converter! * If no conversion is possible, it returns null. **/ public Rel changeConvention(Planner planner, int convention) { return null; } /** * This method is called just before the expression is registered. The * implementation of this method must at least register all child * expressions. */ public void onRegister(Planner planner, int fail) { Rel[] inputs = getInputs(); for (int i = 0; i < inputs.length; i++) { int fail2 = fail; if (fail == Planner.CHILDREN_MUST_BE_REGISTERED) { fail2 = Planner.MUST_BE_REGISTERED; } Rel e = planner.register(inputs[i], fail2); if (e != inputs[i]) { replaceInput(i, e); } } } /** * Returns an estimate of the number of rows this relational expression * will return. */ public double getRows() { return 1.0; } /** * Return the cost of this plan (not including children). */ public Cost computeSelfCost(Planner planner) { // return planner.makeInfiniteCost(); throw Util.newInternal("Infinite cost"); } /** * Create a plan for this expression according to a calling convention. * * @param implementor implementor * @param ordinal indicates our position in the pre-, in- and postfix walk * over the tree; <code>ordinal</code> is -1 when called from the * parent, and <code>i</code> when called from the * <code>i</code><sup>th</sup> child. * * @throws UnsupportedOperationException if this expression cannot be * implemented */ public Object implement(Implementor implementor, int ordinal) { throw new UnsupportedOperationException(); } /** * Returns a value from {@link CallingConvention}. **/ public int getConvention() { return CallingConvention.NONE; } public Expression implementExp(Expression exp, Plan[] plans) { Expression clone = Util.clone(exp); PlanImplementor implementor = new PlanImplementor(this, plans); Expression implementedExp = Util.go(implementor, clone); return implementedExp; } public Expression[] implementExps(Expression[] exps, Plan[] plans) { Expression[] implementedExps = new Expression[exps.length]; for (int i = 0; i < exps.length; i++) { implementedExps[i] = implementExp(exps[i], plans); } return implementedExps; } private static class PlanImplementor extends EvaluationShuttle { PlanImplementor(Rel rel, Plan[] plans) { super(rel.env); } public Expression evaluateDown(Variable p) { String varName = p.toString(); int i = RelEnvironment.getInputOrdinal(varName); if (i >= 0) { // Literal literal = new Literal( // plans[0], OJClass.forClass(Plan.class)); // FunCall funCall = FunCall.create( // "current", new Exp[] {literal}); // FunCall castCall = FunCall.createCast( // OJClass.forClass(Plan.class), funCall); // return castCall; throw new UnsupportedOperationException(); } return null; } }; } // End Rel.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 1853 | Julian Hyde |
saffron: Further improve binding of rows to variables. |
||
#3 | 1801 | Julian Hyde |
saffron: add ObjectSchema; rules can now be matched more than once; started to implement correlations in queries in from list. |
||
#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. |