Skip to content
Browse files

Clean up RelNode.explain, to make it easier to extend. A RelNode deri…

…ved class can now call super.explainTerms, so only needs to describe the attributes it adds over its base class.
  • Loading branch information...
1 parent 02b1c86 commit 4737cbbafc4051d0d70a3887f40461df7f4e3d03 @julianhyde committed Feb 24, 2013
Showing with 389 additions and 510 deletions.
  1. +2 −3 src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
  2. +2 −3 src/main/java/org/eigenbase/oj/rel/IterCalcRel.java
  3. +27 −44 src/main/java/org/eigenbase/rel/AbstractRelNode.java
  4. +11 −29 src/main/java/org/eigenbase/rel/AggregateRelBase.java
  5. +2 −3 src/main/java/org/eigenbase/rel/CalcRelBase.java
  6. +3 −11 src/main/java/org/eigenbase/rel/CorrelatorRel.java
  7. +6 −10 src/main/java/org/eigenbase/rel/EmptyRel.java
  8. +3 −5 src/main/java/org/eigenbase/rel/FilterRelBase.java
  9. +5 −11 src/main/java/org/eigenbase/rel/JoinRel.java
  10. +10 −12 src/main/java/org/eigenbase/rel/JoinRelBase.java
  11. +10 −12 src/main/java/org/eigenbase/rel/ProjectRelBase.java
  12. +11 −0 src/main/java/org/eigenbase/rel/RelFieldCollation.java
  13. +9 −1 src/main/java/org/eigenbase/rel/RelNode.java
  14. +7 −10 src/main/java/org/eigenbase/rel/SamplingRel.java
  15. +7 −10 src/main/java/org/eigenbase/rel/SetOpRel.java
  16. +3 −7 src/main/java/org/eigenbase/rel/SingleRel.java
  17. +10 −21 src/main/java/org/eigenbase/rel/SortRel.java
  18. +3 −6 src/main/java/org/eigenbase/rel/TableAccessRelBase.java
  19. +7 −8 src/main/java/org/eigenbase/rel/TableFunctionRelBase.java
  20. +10 −14 src/main/java/org/eigenbase/rel/TableModificationRelBase.java
  21. +20 −13 src/main/java/org/eigenbase/rel/ValuesRelBase.java
  22. +2 −3 src/main/java/org/eigenbase/rel/WindowedAggregateRel.java
  23. +3 −6 src/main/java/org/eigenbase/rel/jdbc/JdbcQuery.java
  24. +13 −29 src/main/java/org/eigenbase/rel/rules/MultiJoinRel.java
  25. +116 −92 src/main/java/org/eigenbase/relopt/RelOptPlanWriter.java
  26. +0 −1 src/main/java/org/eigenbase/relopt/RelOptUtil.java
  27. +34 −57 src/main/java/org/eigenbase/relopt/RelOptXmlPlanWriter.java
  28. +1 −1 src/main/java/org/eigenbase/relopt/RelTraitDef.java
  29. +6 −2 src/main/java/org/eigenbase/relopt/RelTraitSet.java
  30. +6 −10 src/main/java/org/eigenbase/relopt/volcano/AbstractConverter.java
  31. +11 −8 src/main/java/org/eigenbase/relopt/volcano/RelSubset.java
  32. +23 −57 src/main/java/org/eigenbase/rex/RexProgram.java
  33. +3 −5 src/test/java/org/eigenbase/relopt/volcano/VolcanoPlannerTest.java
  34. +3 −6 src/test/java/org/eigenbase/relopt/volcano/VolcanoPlannerTraitTest.java
View
5 src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
@@ -550,9 +550,8 @@ public PhysType getPhysType() {
return physType;
}
- public void explain(RelOptPlanWriter pw)
- {
- program.explainCalc(this, pw);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return program.explainCalc(super.explainTerms(pw));
}
public double getRows() {
View
5 src/main/java/org/eigenbase/oj/rel/IterCalcRel.java
@@ -105,9 +105,8 @@ public IterCalcRel(
// TODO jvs 10-May-2004: need a computeSelfCost which takes condition into
// account; maybe inherit from CalcRelBase?
- public void explain(RelOptPlanWriter pw)
- {
- program.explainCalc(this, pw);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return program.explainCalc(super.explainTerms(pw));
}
protected String computeDigest()
View
71 src/main/java/org/eigenbase/rel/AbstractRelNode.java
@@ -299,9 +299,20 @@ public RelOptCost computeSelfCost(RelOptPlanner planner)
0);
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(this, Util.emptyStringArray, Util.emptyObjectArray);
+ public final void explain(RelOptPlanWriter pw) {
+ explainTerms(pw).done(this);
+ }
+
+ /** Describes the inputs and attributes of this relational expression.
+ * Each node should call {@code super.explainTerms}, then call the
+ * {@link RelOptPlanWriter#input(String, RelNode)}
+ * and {@link RelOptPlanWriter#item(String, Object)} methods for each input
+ * and attribute.
+ *
+ * @param pw Plan writer
+ */
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return pw;
}
public RelNode onRegister(RelOptPlanner planner)
@@ -380,8 +391,6 @@ public RelOptTable getTable()
/**
* Computes the digest. Does not modify this object.
- *
- * @post return != null
*/
protected String computeDigest()
{
@@ -391,54 +400,28 @@ protected String computeDigest()
new PrintWriter(sw),
SqlExplainLevel.DIGEST_ATTRIBUTES)
{
- public void explain(
- RelNode rel,
- String [] terms,
- Object [] values)
+ protected void explain_(
+ RelNode rel, List<Pair<String, Object>> values)
{
- List<RelNode> inputs = rel.getInputs();
- RexNode [] childExps = rel.getChildExps();
- assert terms.length
- == (inputs.size() + childExps.length + values.length)
- : "terms.length="
- + terms.length
- + " inputs.length=" + inputs.size()
- + " childExps.length=" + childExps.length
- + " values.length=" + values.length;
- write(getRelTypeName());
-
- for (int i = 0; i < traitSet.size(); i++) {
- write(".");
- write(traitSet.getTrait(i).toString());
+ pw.write(getRelTypeName());
+
+ for (RelTrait trait : traitSet) {
+ pw.write(".");
+ pw.write(trait.toString());
}
- write("(");
+ pw.write("(");
int j = 0;
- for (int i = 0; i < inputs.size(); i++) {
- if (j > 0) {
- write(",");
- }
- write(terms[j++] + "=" + inputs.get(i).getDigest());
- }
- for (int i = 0; i < childExps.length; i++) {
- if (j > 0) {
- write(",");
- }
- RexNode childExp = childExps[i];
- write(terms[j++] + "=" + childExp.toString());
- }
- for (int i = 0; i < values.length; i++) {
- Object value = values[i];
- if (j > 0) {
- write(",");
+ for (Pair<String, Object> value : values) {
+ if (j++ > 0) {
+ pw.write(",");
}
- write(terms[j++] + "=" + value);
+ pw.write(value.left + "=" + value.right);
}
- write(")");
+ pw.write(")");
}
};
explain(pw);
- pw.flush();
return sw.toString();
}
}
View
40 src/main/java/org/eigenbase/rel/AggregateRelBase.java
@@ -27,6 +27,8 @@
import org.eigenbase.sql.validate.*;
import org.eigenbase.util.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* <code>AggregateRelBase</code> is an abstract base class for implementations
@@ -120,39 +122,19 @@ public BitSet getGroupSet()
return groupSet;
}
- public void explain(RelOptPlanWriter pw)
- {
- List<String> names = new ArrayList<String>();
- List<Object> values = new ArrayList<Object>();
- populateExplainAttributes(names, values);
- pw.explain(this, names, values);
- }
-
- /**
- * Populates attributes for EXPLAIN.
- *
- * @param names Names of attributes
- * @param values Values of attributes
- */
- protected void populateExplainAttributes(
- List<String> names,
- List<Object> values)
- {
- names.add("child");
- names.add("group");
- values.add(groupSet);
- int i = -1;
- for (AggregateCall aggCall : aggCalls) {
- ++i;
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ super.explainTerms(pw)
+ .item("group", groupSet);
+ for (Ord<AggregateCall> ord : Ord.zip(aggCalls)) {
final String name;
- if (aggCall.getName() != null) {
- name = aggCall.getName();
+ if (ord.e.getName() != null) {
+ name = ord.e.getName();
} else {
- name = "agg#" + i;
+ name = "agg#" + ord.i;
}
- names.add(name);
- values.add(aggCall);
+ pw.item(name, ord.e);
}
+ return pw;
}
// implement RelNode
View
5 src/main/java/org/eigenbase/rel/CalcRelBase.java
@@ -129,9 +129,8 @@ public RelOptCost computeSelfCost(RelOptPlanner planner)
return RexNode.EMPTY_ARRAY;
}
- public void explain(RelOptPlanWriter pw)
- {
- program.explainCalc(this, pw);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return program.explainCalc(super.explainTerms(pw));
}
}
View
14 src/main/java/org/eigenbase/rel/CorrelatorRel.java
@@ -120,17 +120,9 @@ public CorrelatorRel copy(
joinType);
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] {
- "left", "right", "condition", "joinType", "correlations"
- },
- new Object[] {
- joinType.name().toLowerCase(),
- correlations
- });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("correlations", correlations);
}
/**
View
16 src/main/java/org/eigenbase/rel/EmptyRel.java
@@ -93,19 +93,15 @@ public double getRows()
}
// implement RelNode
- public void explain(RelOptPlanWriter pw)
- {
- if (pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES) {
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
// For rel digest, include the row type to discriminate
// this from other empties with different row types.
- pw.explain(
- this,
- new String[] { "type", },
- new Object[] { rowType });
- } else {
// For normal EXPLAIN PLAN, omit the type.
- super.explain(pw);
- }
+ .itemIf(
+ "type",
+ rowType,
+ pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES);
}
}
View
8 src/main/java/org/eigenbase/rel/FilterRelBase.java
@@ -107,11 +107,9 @@ public static double estimateFilteredRows(RelNode child, RexNode condition)
* RelMetadataQuery.getSelectivity(child, condition);
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] { "child", "condition" });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("condition", condition);
}
}
View
16 src/main/java/org/eigenbase/rel/JoinRel.java
@@ -146,22 +146,16 @@ public JoinRel copy(
systemFieldList);
}
- public void explain(RelOptPlanWriter pw)
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw)
{
// NOTE jvs 14-Mar-2006: Do it this way so that semijoin state
// don't clutter things up in optimizers that don't use semijoins
if (!semiJoinDone) {
- super.explain(pw);
- return;
+ return super.explainTerms(pw);
}
- pw.explain(
- this,
- new String[] {
- "left", "right", "condition", "joinType", "semiJoinDone"
- },
- new Object[] {
- joinType.name().toLowerCase(), semiJoinDone
- });
+ return super.explainTerms(pw)
+ .item("joinType", joinType.name().toLowerCase())
+ .item("semiJoinDone", semiJoinDone);
}
/**
View
22 src/main/java/org/eigenbase/rel/JoinRelBase.java
@@ -201,18 +201,16 @@ public void childrenAccept(RelVisitor visitor)
visitor.visit(right, 1, this);
}
- public void explain(RelOptPlanWriter pw)
- {
- final List<String> nameList =
- new ArrayList<String>(Arrays.asList("left", "right", "condition"));
- final List<Object> valueList = new ArrayList<Object>();
- nameList.add("joinType");
- valueList.add(joinType.name().toLowerCase());
- if (!getSystemFieldList().isEmpty()) {
- nameList.add("systemFields");
- valueList.add(getSystemFieldList());
- }
- pw.explain(this, nameList, valueList);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .input("left", left)
+ .input("right", right)
+ .item("condition", condition)
+ .item("joinType", joinType.name().toLowerCase())
+ .itemIf(
+ "systemFields",
+ getSystemFieldList(),
+ !getSystemFieldList().isEmpty());
}
public void registerStoppedVariable(String name)
View
22 src/main/java/org/eigenbase/rel/ProjectRelBase.java
@@ -26,6 +26,8 @@
import org.eigenbase.rex.*;
import org.eigenbase.sql.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* <code>ProjectRelBase</code> is an abstract base class for implementations of
@@ -159,17 +161,14 @@ public RelOptCost computeSelfCost(RelOptPlanner planner)
return planner.makeCost(dRows, dCpu, dIo);
}
- public void explain(RelOptPlanWriter pw)
- {
- List<String> terms = new ArrayList<String>();
- List<Object> values = new ArrayList<Object>();
- terms.add("child");
- for (RelDataTypeField field : rowType.getFields()) {
- String fieldName = field.getName();
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ super.explainTerms(pw);
+ for (Ord<RelDataTypeField> field : Ord.zip(rowType.getFields())) {
+ String fieldName = field.e.getName();
if (fieldName == null) {
- fieldName = "field#" + (terms.size() - 1);
+ fieldName = "field#" + field.i;
}
- terms.add(fieldName);
+ pw.item(fieldName, exps[field.i]);
}
// If we're generating a digest, include the rowtype. If two projects
@@ -179,11 +178,10 @@ public void explain(RelOptPlanWriter pw)
if ((pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES)
&& false)
{
- terms.add("type");
- values.add(rowType);
+ pw.item("type", rowType);
}
- pw.explain(this, terms, values);
+ return pw;
}
/**
View
11 src/main/java/org/eigenbase/rel/RelFieldCollation.java
@@ -168,6 +168,17 @@ public String toString()
? ""
: " " + nullDirection);
}
+
+ public String shortString() {
+ switch (nullDirection) {
+ case FIRST:
+ return direction + "-nulls-first";
+ case LAST:
+ return direction + "-nulls-last";
+ default:
+ return direction.toString();
+ }
+ }
}
// End RelFieldCollation.java
View
10 src/main/java/org/eigenbase/rel/RelNode.java
@@ -213,6 +213,14 @@
*/
public RelOptCost computeSelfCost(RelOptPlanner planner);
+ /** Describes the inputs and attributes of this relational expression.
+ * Each node should call {@code super.explain}, then call the
+ * {@link RelOptPlanWriter#input(String, RelNode)}
+ * and {@link RelOptPlanWriter#item(String, Object)} methods for each input
+ * and attribute.
+ *
+ * @param pw Plan writer
+ */
public void explain(RelOptPlanWriter pw);
/**
@@ -250,7 +258,7 @@ public void replaceInput(
/**
* Returns the name of this relational expression's class, sans package
- * name, for use in {@link #explain}. For example, for a <code>
+ * name, for use in explain. For example, for a <code>
* org.eigenbase.rel.ArrayRel.ArrayReader</code>, this method returns
* "ArrayReader".
*/
View
17 src/main/java/org/eigenbase/rel/SamplingRel.java
@@ -68,16 +68,13 @@ public RelOptSamplingParameters getSamplingParameters()
}
// implement RelNode
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] { "child", "mode", "rate", "repeatableSeed" },
- new Object[] {
- params.isBernoulli() ? "bernoulli" : "system",
- params.getSamplingPercentage(),
- params.isRepeatable() ? params.getRepeatableSeed() : "-"
- });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("mode", params.isBernoulli() ? "bernoulli" : "system")
+ .item("rate", params.getSamplingPercentage())
+ .item(
+ "repeatableSeed",
+ params.isRepeatable() ? params.getRepeatableSeed() : "-");
}
}
View
17 src/main/java/org/eigenbase/rel/SetOpRel.java
@@ -23,6 +23,8 @@
import org.eigenbase.relopt.*;
import org.eigenbase.reltype.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* <code>SetOpRel</code> is an abstract base for relational set operators such
@@ -76,17 +78,12 @@ public boolean isDistinct()
return inputs;
}
- public void explain(RelOptPlanWriter pw)
- {
- String [] terms = new String[inputs.size() + 1];
- for (int i = 0; i < inputs.size(); i++) {
- terms[i] = "input#" + i;
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ super.explainTerms(pw);
+ for (Ord<RelNode> ord : Ord.zip(inputs)) {
+ pw.input("input#" + ord.i, ord.e);
}
- terms[inputs.size()] = "all";
- pw.explain(
- this,
- terms,
- new Object[] { Boolean.valueOf(all) });
+ return pw.item("all", all);
}
protected RelDataType deriveRowType()
View
10 src/main/java/org/eigenbase/rel/SingleRel.java
@@ -23,7 +23,6 @@
import org.eigenbase.rel.metadata.*;
import org.eigenbase.relopt.*;
import org.eigenbase.reltype.*;
-import org.eigenbase.util.*;
/**
@@ -82,12 +81,9 @@ public void childrenAccept(RelVisitor visitor)
visitor.visit(child, 0, this);
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] { "child" },
- Util.emptyObjectArray);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .input("child", getChild());
}
// override Rel
View
31 src/main/java/org/eigenbase/rel/SortRel.java
@@ -23,6 +23,8 @@
import org.eigenbase.reltype.*;
import org.eigenbase.rex.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* Relational expression which imposes a particular sort order on its input
@@ -99,29 +101,16 @@ public SortRel copy(
return collations;
}
- public void explain(RelOptPlanWriter pw)
- {
- String [] terms = new String[1 + (collations.size() * 2)];
- Object [] values = new Object[collations.size()];
- int i = 0;
- terms[i++] = "child";
- for (int j = 0; j < collations.size(); ++j) {
- terms[i++] = "sort" + j;
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ super.explainTerms(pw);
+ assert fieldExps.length == collations.size();
+ for (Ord<RexNode> ord : Ord.zip(fieldExps)) {
+ pw.item("sort" + ord.i, ord.e);
}
- for (int j = 0; j < collations.size(); ++j) {
- terms[i++] = "dir" + j;
- final RelFieldCollation collation = collations.get(j);
- values[j] = collation.getDirection().toString();
- switch (collation.nullDirection) {
- case FIRST:
- values[j] = ((String) values[j]) + "-nulls-first";
- break;
- case LAST:
- values[j] = ((String) values[j]) + "-nulls-last";
- break;
- }
+ for (Ord<RelFieldCollation> ord : Ord.zip(collations)) {
+ pw.item("dir" + ord.i, ord.e.shortString());
}
- pw.explain(this, terms, values);
+ return pw;
}
}
View
9 src/main/java/org/eigenbase/rel/TableAccessRelBase.java
@@ -87,12 +87,9 @@ public RelDataType deriveRowType()
return table.getRowType();
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] { "table" },
- new Object[] { Arrays.asList(table.getQualifiedName()) });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("table", Arrays.asList(table.getQualifiedName()));
}
/**
View
15 src/main/java/org/eigenbase/rel/TableFunctionRelBase.java
@@ -24,6 +24,8 @@
import org.eigenbase.reltype.*;
import org.eigenbase.rex.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* <code>TableFunctionRelBase</code> is an abstract base class for
@@ -111,15 +113,12 @@ public RexNode getCall()
return rexCall;
}
- public void explain(RelOptPlanWriter pw)
- {
- String [] terms = new String[inputs.size() + 1];
- for (int i = 0; i < inputs.size(); i++) {
- terms[i] = "input#" + i;
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ super.explainTerms(pw);
+ for (Ord<RelNode> ord : Ord.zip(inputs)) {
+ pw.input("input#" + ord.i, ord.e);
}
- terms[inputs.size()] = "invocation";
-
- pw.explain(this, terms);
+ return pw.item("invocation", rexCall);
}
/**
View
24 src/main/java/org/eigenbase/rel/TableModificationRelBase.java
@@ -186,20 +186,16 @@ public RelDataType getExpectedInputRowType(int ordinalInParent)
return inputRowType;
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] {
- "child", "table", "operation", "updateColumnList",
- "flattened"
- },
- new Object[] {
- Arrays.asList(table.getQualifiedName()), getOperation(),
- (updateColumnList == null) ? Collections.EMPTY_LIST
- : updateColumnList,
- flattened
- });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("table", Arrays.asList(table.getQualifiedName()))
+ .item("operation", getOperation())
+ .item(
+ "updateColumnList",
+ (updateColumnList == null)
+ ? Collections.EMPTY_LIST
+ : updateColumnList)
+ .item("flattened", flattened);
}
// implement RelNode
View
33 src/main/java/org/eigenbase/rel/ValuesRelBase.java
@@ -27,6 +27,9 @@
import org.eigenbase.sql.type.*;
import org.eigenbase.util.Pair;
+import net.hydromatic.linq4j.function.Function1;
+import net.hydromatic.linq4j.function.Functions;
+
/**
* <code>ValuesRelBase</code> is an abstract base class for implementations of
@@ -38,6 +41,17 @@
public abstract class ValuesRelBase
extends AbstractRelNode
{
+ /** Lambda that helps render tuples as strings. */
+ private static final Function1<List<RexLiteral>,Object> F =
+ new Function1<List<RexLiteral>, Object>() {
+ public Object apply(List<RexLiteral> tuple) {
+ String s = tuple.toString();
+ assert s.startsWith("[");
+ assert s.endsWith("]");
+ return "{ " + s.substring(1, s.length() - 1) + " }";
+ }
+ };
+
//~ Instance fields --------------------------------------------------------
protected final List<List<RexLiteral>> tuples;
@@ -127,7 +141,7 @@ public double getRows()
}
// implement RelNode
- public void explain(RelOptPlanWriter pw)
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw)
{
// A little adapter just to get the tuples to come out
// with curly brackets instead of square brackets. Plus
@@ -139,20 +153,13 @@ public void explain(RelOptPlanWriter pw)
assert (s.endsWith("]"));
renderList.add("{ " + s.substring(1, s.length() - 1) + " }");
}
- if (pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES) {
+ return super.explainTerms(pw)
// For rel digest, include the row type since a rendered
// literal may leave the type ambiguous (e.g. "null").
- pw.explain(
- this,
- new String[] { "type", "tuples" },
- new Object[] { rowType, renderList });
- } else {
- // For normal EXPLAIN PLAN, omit the type.
- pw.explain(
- this,
- new String[] { "tuples" },
- new Object[] { renderList });
- }
+ .itemIf(
+ "type", rowType,
+ pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES)
+ .item("tuples", Functions.adapt(tuples, F));
}
}
View
5 src/main/java/org/eigenbase/rel/WindowedAggregateRel.java
@@ -107,9 +107,8 @@ public RexProgram getProgram()
return program;
}
- public void explain(RelOptPlanWriter pw)
- {
- program.explainCalc(this, pw);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return program.explainCalc(super.explainTerms(pw));
}
public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs)
View
9 src/main/java/org/eigenbase/rel/jdbc/JdbcQuery.java
@@ -136,12 +136,9 @@ public SqlDialect getDialect()
}
// override RelNode
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] { "foreignSql" },
- new Object[] { getForeignSql() });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("foreignSql", getForeignSql());
}
/**
View
42 src/main/java/org/eigenbase/rel/rules/MultiJoinRel.java
@@ -24,6 +24,8 @@
import org.eigenbase.reltype.*;
import org.eigenbase.rex.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* A MultiJoinRel represents a join of N inputs, whereas other join relnodes
@@ -125,26 +127,11 @@ public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
return clonedMap;
}
- public void explain(RelOptPlanWriter pw)
- {
- int nInputs = inputs.size();
- int nExtraTerms = (postJoinFilter != null) ? 6 : 5;
- String [] terms = new String[nInputs + nExtraTerms];
- for (int i = 0; i < nInputs; i++) {
- terms[i] = "input#" + i;
- }
- terms[nInputs] = "joinFilter";
- terms[nInputs + 1] = "isFullOuterJoin";
- terms[nInputs + 2] = "joinTypes";
- terms[nInputs + 3] = "outerJoinConditions";
- terms[nInputs + 4] = "projFields";
- if (postJoinFilter != null) {
- terms[nInputs + 5] = "postJoinFilter";
- }
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
List<String> joinTypeNames = new ArrayList<String>();
List<String> outerJoinConds = new ArrayList<String>();
List<String> projFieldObjects = new ArrayList<String>();
- for (int i = 0; i < nInputs; i++) {
+ for (int i = 0; i < inputs.size(); i++) {
joinTypeNames.add(joinTypes[i].name());
if (outerJoinConditions[i] == null) {
outerJoinConds.add("NULL");
@@ -158,19 +145,16 @@ public void explain(RelOptPlanWriter pw)
}
}
- // Note that we don't need to include the join field reference counts
- // in the digest because that field does not change for a given set
- // of inputs
- Object [] objects = new Object[nExtraTerms - 1];
- objects[0] = isFullOuterJoin;
- objects[1] = joinTypeNames;
- objects[2] = outerJoinConds;
- objects[3] = projFieldObjects;
- if (postJoinFilter != null) {
- objects[4] = postJoinFilter;
+ super.explainTerms(pw);
+ for (Ord<RelNode> ord : Ord.zip(inputs)) {
+ pw.input("input#" + ord.i, ord.e);
}
-
- pw.explain(this, terms, objects);
+ return pw.item("joinFilter", joinFilter)
+ .item("isFullOuterJoin", isFullOuterJoin)
+ .item("joinTypes", joinTypeNames)
+ .item("outerJoinConditions", outerJoinConds)
+ .item("projFields", projFieldObjects)
+ .itemIf("postJoinFilter", postJoinFilter, postJoinFilter != null);
}
public RelDataType deriveRowType()
View
208 src/main/java/org/eigenbase/relopt/RelOptPlanWriter.java
@@ -17,6 +17,7 @@
*/
package org.eigenbase.relopt;
+import java.io.PrintWriter;
import java.util.*;
import org.eigenbase.rel.*;
@@ -25,33 +26,35 @@
import org.eigenbase.sql.*;
import org.eigenbase.util.*;
+import net.hydromatic.optiq.runtime.Spacer;
+
+import net.hydromatic.linq4j.Ord;
+
/**
* Callback for an expression to dump itself to.
*/
-public class RelOptPlanWriter
- extends java.io.PrintWriter
-{
+public class RelOptPlanWriter {
//~ Instance fields --------------------------------------------------------
private boolean withIdPrefix = true;
-
+ protected final PrintWriter pw;
private final SqlExplainLevel detailLevel;
- int level;
+ protected final Spacer spacer = new Spacer();
+ private final List<Pair<String, Object>> values =
+ new ArrayList<Pair<String, Object>>();
//~ Constructors -----------------------------------------------------------
- public RelOptPlanWriter(java.io.PrintWriter pw)
- {
+ public RelOptPlanWriter(PrintWriter pw) {
this(pw, SqlExplainLevel.EXPPLAN_ATTRIBUTES);
}
public RelOptPlanWriter(
- java.io.PrintWriter pw,
+ PrintWriter pw,
SqlExplainLevel detailLevel)
{
- super(pw);
- this.level = 0;
+ this.pw = pw;
this.detailLevel = detailLevel;
}
@@ -62,24 +65,9 @@ public void setIdPrefix(boolean b)
withIdPrefix = b;
}
- /**
- * Prints the plan of a given relational expression to this writer.
- *
- * <p>The terms and values array must be specified. Individual values may
- * be null.</p>
- *
- * @param rel Relational expression
- * @param terms Names of the attributes of the plan
- * @param values Values of the attributes of the plan
- *
- * @pre rel != null
- * @pre terms.length == rel.getChildExps().length + values.length
- * @pre values != null
- */
- public void explain(
+ protected void explain_(
RelNode rel,
- String [] terms,
- Object [] values)
+ List<Pair<String, Object>> values)
{
List<RelNode> inputs = rel.getInputs();
@@ -92,85 +80,66 @@ public void explain(
return;
}
- RexNode [] children = rel.getChildExps();
- assert terms.length
- == (inputs.size() + children.length
- + values.length) : "terms.length=" + terms.length
- + " inputs.length=" + inputs.size() + " children.length="
- + children.length + " values.length=" + values.length;
- String s;
+ StringBuilder s = new StringBuilder();
if (withIdPrefix) {
- s = rel.getId() + ":";
- } else {
- s = "";
+ s.append(rel.getId()).append(":");
}
- s = s + rel.getRelTypeName();
-
- for (int i = 0; i < level; i++) {
- print(" ");
- }
- print(s);
+ spacer.spaces(s);
+ s.append(rel.getRelTypeName());
if (detailLevel != SqlExplainLevel.NO_ATTRIBUTES) {
int j = 0;
- for (int i = 0; i < children.length; i++) {
- RexNode child = children[i];
- print(
- ((j == 0) ? "(" : ", ")
- + terms[inputs.size() + j++] + "=["
- + child.toString() + "]");
- }
- for (int i = 0; i < values.length; i++) {
- Object value = values[i];
- print(
- ((j == 0) ? "(" : ", ")
- + terms[inputs.size() + j++] + "=["
- + value + "]");
+ for (Pair<String, Object> value : values) {
+ if (value.right instanceof RelNode) {
+ continue;
+ }
+ if (j++ == 0) {
+ s.append("(");
+ } else {
+ s.append(", ");
+ }
+ s.append(value.left)
+ .append("=[")
+ .append(value.right)
+ .append("]");
}
if (j > 0) {
- print(")");
+ s.append(")");
}
}
if (detailLevel == SqlExplainLevel.ALL_ATTRIBUTES) {
- print(": rowcount = " + RelMetadataQuery.getRowCount(rel));
- print(", cumulative cost = ");
- print(RelMetadataQuery.getCumulativeCost(rel));
+ s.append(": rowcount = ")
+ .append(RelMetadataQuery.getRowCount(rel))
+ .append(", cumulative cost = ")
+ .append(RelMetadataQuery.getCumulativeCost(rel));
}
- println("");
- level++;
+ pw.println(s);
+ spacer.add(2);
explainInputs(inputs);
- level--;
+ spacer.subtract(2);
}
- private void explainInputs(List<RelNode> inputs)
- {
- for (int i = 0; i < inputs.size(); i++) {
- RelNode child = inputs.get(i);
- child.explain(this);
+ private void explainInputs(List<RelNode> inputs) {
+ for (RelNode input : inputs) {
+ input.explain(this);
}
}
- public void explain(
- RelNode rel,
- String [] terms)
- {
- explain(rel, terms, Util.emptyStringArray);
- }
-
/**
- * Shorthand for {@link #explain(RelNode, String[], Object[])}.
+ * Prints an explanation of a node, with a list of (term, value) pairs.
+ *
+ * <p>The term-value pairs are generally gathered by calling
+ * {@link RelNode#explain(RelOptPlanWriter)}. Each sub-class of
+ * {@link RelNode} calls {@link #input(String, org.eigenbase.rel.RelNode)}
+ * and {@link #item(String, Object)} to declare term-value pairs.</p>
*
* @param rel Relational expression
- * @param termList List of names of the attributes of the plan
- * @param valueList List of values of the attributes of the plan
+ * @param valueList List of term-value pairs
*/
public final void explain(
RelNode rel,
- List<String> termList,
- List<Object> valueList)
+ List<Pair<String, Object>> valueList)
{
- String [] terms = termList.toArray(new String[termList.size()]);
- Object [] values = valueList.toArray(new Object[valueList.size()]);
- explain(rel, terms, values);
+ explain_(rel, valueList);
}
/**
@@ -181,16 +150,10 @@ public void explainSubset(
String s,
RelNode child)
{
- print(s);
- level++;
+ pw.print(s);
+ spacer.add(2);
child.explain(this);
- level--;
- }
-
- public void explainTree(RelNode exp)
- {
- this.level = 0;
- exp.explain(this);
+ spacer.subtract(2);
}
/**
@@ -200,6 +163,67 @@ public SqlExplainLevel getDetailLevel()
{
return detailLevel;
}
+
+ /** Adds an input to the explanation of the current node.
+ *
+ * @param term Term for input, e.g. "left" or "input #1".
+ * @param input Input relational expression
+ */
+ public RelOptPlanWriter input(String term, RelNode input) {
+ values.add(Pair.of(term, (Object) input));
+ return this;
+ }
+
+ /** Adds an attribute to the explanation of the current node.
+ *
+ * @param term Term for attribute, e.g. "joinType"
+ * @param value Attribute value
+ */
+ public RelOptPlanWriter item(String term, Object value) {
+ values.add(Pair.of(term, value));
+ return this;
+ }
+
+ /** Adds an input to the explanation of the current node, if a condition
+ * holds. */
+ public RelOptPlanWriter itemIf(String term, Object value, boolean condition)
+ {
+ if (condition) {
+ item(term, value);
+ }
+ return this;
+ }
+
+ /** Writes the completed explanation. */
+ public RelOptPlanWriter done(RelNode node) {
+ int i = 0;
+ for (RelNode input : node.getInputs()) {
+ assert values.get(i++).right == input;
+ }
+ for (RexNode expr : node.getChildExps()) {
+ assert values.get(i++).right == expr;
+ }
+ final List<Pair<String, Object>> valuesCopy =
+ new ArrayList<Pair<String, Object>>(values);
+ values.clear();
+ explain_(node, valuesCopy);
+ pw.flush();
+ return this;
+ }
+
+ /** Converts the collected terms and values to a string. Does not write to
+ * the parent writer. */
+ public String simple() {
+ final StringBuilder buf = new StringBuilder("(");
+ for (Ord<Pair<String, Object>> ord : Ord.zip(values)) {
+ if (ord.i > 0) {
+ buf.append(", ");
+ }
+ buf.append(ord.e.left).append("=[").append(ord.e.right).append("]");
+ }
+ buf.append(")");
+ return buf.toString();
+ }
}
// End RelOptPlanWriter.java
View
1 src/main/java/org/eigenbase/relopt/RelOptUtil.java
@@ -1905,7 +1905,6 @@ public static String toString(final RelNode rel)
new RelOptPlanWriter(new PrintWriter(sw));
planWriter.setIdPrefix(false);
rel.explain(planWriter);
- planWriter.flush();
return sw.toString();
}
View
91 src/main/java/org/eigenbase/relopt/RelOptXmlPlanWriter.java
@@ -18,11 +18,11 @@
package org.eigenbase.relopt;
import java.io.*;
-import java.util.List;
+import java.util.*;
import org.eigenbase.rel.*;
-import org.eigenbase.rex.*;
import org.eigenbase.sql.*;
+import org.eigenbase.util.Pair;
import org.eigenbase.xom.*;
@@ -46,19 +46,21 @@
public RelOptXmlPlanWriter(PrintWriter pw, SqlExplainLevel detailLevel)
{
super(pw, detailLevel);
- xmlOutput = new XMLOutput(this);
+ xmlOutput = new XMLOutput(pw);
xmlOutput.setGlob(true);
xmlOutput.setCompact(false);
}
//~ Methods ----------------------------------------------------------------
- public void explain(RelNode rel, String [] terms, Object [] values)
+ protected void explain_(
+ RelNode rel,
+ List<Pair<String, Object>> values)
{
if (generic) {
- explainGeneric(rel, terms, values);
+ explainGeneric(rel, values);
} else {
- explainSpecific(rel, terms, values);
+ explainSpecific(rel, values);
}
}
@@ -88,51 +90,40 @@ public void explain(RelNode rel, String [] terms, Object [] values)
* </blockquote>
*
* @param rel Relational expression
- * @param terms Names of the attributes of the plan
- * @param values Values of the attributes of the plan
+ * @param values List of term-value pairs
*/
private void explainGeneric(
RelNode rel,
- String [] terms,
- Object [] values)
+ List<Pair<String, Object>> values)
{
- List<RelNode> inputs = rel.getInputs();
- RexNode [] children = rel.getChildExps();
- assert terms.length
- == (inputs.size() + children.length
- + values.length) : "terms.length=" + terms.length
- + " inputs.length=" + inputs.size() + " children.length="
- + children.length + " values.length=" + values.length;
String relType = rel.getRelTypeName();
xmlOutput.beginBeginTag("RelNode");
xmlOutput.attribute("type", relType);
//xmlOutput.attribute("id", rel.getId() + "");
xmlOutput.endBeginTag("RelNode");
- int j = 0;
- for (RexNode child : children) {
+ final List<RelNode> inputs = new ArrayList<RelNode>();
+ for (Pair<String, Object> pair : values) {
+ if (pair.right instanceof RelNode) {
+ inputs.add((RelNode) pair.right);
+ continue;
+ }
+ if (pair.right == null) {
+ continue;
+ }
xmlOutput.beginBeginTag("Property");
- xmlOutput.attribute("name", terms[inputs.size() + j++]);
+ xmlOutput.attribute("name", pair.left);
xmlOutput.endBeginTag("Property");
- xmlOutput.cdata(child.toString());
+ xmlOutput.cdata(pair.right.toString());
xmlOutput.endTag("Property");
}
- for (Object value : values) {
- if (value != null) {
- xmlOutput.beginBeginTag("Property");
- xmlOutput.attribute("name", terms[inputs.size() + j++]);
- xmlOutput.endBeginTag("Property");
- xmlOutput.cdata(value.toString());
- xmlOutput.endTag("Property");
- }
- }
xmlOutput.beginTag("Inputs", null);
- level++;
+ spacer.add(2);
for (RelNode input : inputs) {
input.explain(this);
}
- level--;
+ spacer.subtract(2);
xmlOutput.endTag("Inputs");
xmlOutput.endTag("RelNode");
}
@@ -149,44 +140,30 @@ private void explainGeneric(
* </pre>
*
* @param rel Relational expression
- * @param terms Names of the attributes of the plan
- * @param values Values of the attributes of the plan
+ * @param values List of term-value pairs
*/
private void explainSpecific(
RelNode rel,
- String [] terms,
- Object [] values)
+ List<Pair<String, Object>> values)
{
- List<RelNode> inputs = rel.getInputs();
- RexNode [] children = rel.getChildExps();
- assert terms.length
- == (inputs.size() + children.length
- + values.length) : "terms.length=" + terms.length
- + " inputs.length=" + inputs.size() + " children.length="
- + children.length + " values.length=" + values.length;
String tagName = rel.getRelTypeName();
xmlOutput.beginBeginTag(tagName);
xmlOutput.attribute("id", rel.getId() + "");
- int j = 0;
- for (RexNode child : children) {
- xmlOutput.attribute(
- terms[inputs.size() + j++],
- child.toString());
- }
- for (Object value : values) {
- if (value != null) {
- xmlOutput.attribute(
- terms[inputs.size() + j++],
- value.toString());
+ for (Pair<String, Object> value : values) {
+ if (value.right instanceof RelNode) {
+ continue;
}
+ xmlOutput.attribute(
+ value.left,
+ value.right.toString());
}
xmlOutput.endBeginTag(tagName);
- level++;
- for (RelNode input : inputs) {
+ spacer.add(2);
+ for (RelNode input : rel.getInputs()) {
input.explain(this);
}
- level--;
+ spacer.subtract(2);
}
}
View
2 src/main/java/org/eigenbase/relopt/RelTraitDef.java
@@ -75,7 +75,7 @@ public RelTraitDef()
/**
* @return a simple name for this RelTraitDef (for use in {@link
- * org.eigenbase.rel.RelNode#explain(RelOptPlanWriter)}).
+ * org.eigenbase.rel.RelNode#explainTerms(RelOptPlanWriter)}).
*/
public abstract String getSimpleName();
View
8 src/main/java/org/eigenbase/relopt/RelTraitSet.java
@@ -28,9 +28,9 @@
* @author Stephan Zuercher
* @version $Id$
*/
-public class RelTraitSet
-{
+public final class RelTraitSet extends AbstractList<RelTrait> {
public static final RelTrait[] EMPTY_TRAITS = new RelTrait[0];
+
//~ Instance fields --------------------------------------------------------
private final Cache cache;
@@ -79,6 +79,10 @@ public RelTrait getTrait(int index)
return traits[index];
}
+ public RelTrait get(int index) {
+ return getTrait(index);
+ }
+
/**
* Retrieves a RelTrait of the given type from the set.
*
View
16 src/main/java/org/eigenbase/relopt/volcano/AbstractConverter.java
@@ -79,17 +79,13 @@ public RelOptCost computeSelfCost(RelOptPlanner planner)
return planner.makeInfiniteCost();
}
- public void explain(RelOptPlanWriter pw)
- {
- String [] terms = new String[traitSet.size() + 1];
- Object [] values = new Object[traitSet.size()];
- terms[0] = "child";
- for (int i = 0; i < traitSet.size(); i++) {
- terms[i + 1] = traitSet.getTrait(i).getTraitDef().getSimpleName();
- values[i] = traitSet.getTrait(i);
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ super.explainTerms(pw)
+ .input("child", getChild());
+ for (RelTrait trait : traitSet) {
+ pw.item(trait.getTraitDef().getSimpleName(), trait);
}
-
- pw.explain(this, terms, values);
+ return pw;
}
//~ Inner Classes ----------------------------------------------------------
View
19 src/main/java/org/eigenbase/relopt/volcano/RelSubset.java
@@ -18,7 +18,6 @@
package org.eigenbase.relopt.volcano;
import java.io.*;
-
import java.util.*;
import java.util.logging.*;
@@ -29,6 +28,8 @@
import org.eigenbase.trace.*;
import org.eigenbase.util.*;
+import net.hydromatic.linq4j.Ord;
+
/**
* A <code>RelSubset</code> is set of expressions in a set which have the same
@@ -149,29 +150,31 @@ public double getRows()
}
// implement RelNode
- public void explain(RelOptPlanWriter pw)
- {
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ // Not a typical implementation of "explain". We don't gather terms &
+ // values to be printed later. We actually do the work.
StringBuilder s = new StringBuilder();
s.append(id).append(": RelSubset(");
- for (int i = 0; i < traitSet.size(); i++) {
- if (i > 0) {
+ for (Ord<RelTrait> ord : Ord.zip(traitSet)) {
+ if (ord.i > 0) {
s.append(", ");
}
- s.append(traitSet.getTrait(i));
+ s.append(ord.e);
}
s.append(')');
pw.explainSubset(
s.toString(),
rels.get(0));
+ return pw;
}
protected String computeDigest()
{
StringBuilder digest = new StringBuilder("Subset#");
digest.append(set.id);
- for (int i = 0; i < traitSet.size(); i++) {
- digest.append('.').append(traitSet.getTrait(i));
+ for (RelTrait trait : traitSet) {
+ digest.append('.').append(trait);
}
return digest.toString();
}
View
80 src/main/java/org/eigenbase/rex/RexProgram.java
@@ -17,6 +17,8 @@
*/
package org.eigenbase.rex;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.*;
import org.eigenbase.rel.*;
@@ -239,59 +241,29 @@ public String toString()
{
// Intended to produce similar output to explainCalc,
// but without requiring a RelNode or RelOptPlanWriter.
- List<String> termList = new ArrayList<String>();
- List<Object> valueList = new ArrayList<Object>();
- collectExplainTerms("", termList, valueList);
- final StringBuilder buf = new StringBuilder("(");
- for (int i = 0; i < valueList.size(); i++) {
- if (i > 0) {
- buf.append(", ");
- }
- buf.append(termList.get(i)).append("=[").append(valueList.get(i))
- .append("]");
- }
- buf.append(")");
- return buf.toString();
+ final RelOptPlanWriter pw =
+ new RelOptPlanWriter(new PrintWriter(new StringWriter()));
+ collectExplainTerms("", pw);
+ return pw.simple();
}
/**
* Writes an explanation of the expressions in this program to a plan
* writer.
*
- * @param rel Relational expression which owns this program
* @param pw Plan writer
*/
- public void explainCalc(
- RelNode rel,
- RelOptPlanWriter pw)
- {
- List<String> termList = new ArrayList<String>();
- List<Object> valueList = new ArrayList<Object>();
- termList.add("child");
- collectExplainTerms("", termList, valueList, pw.getDetailLevel());
-
- if ((pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES)
- && false)
- {
- termList.add("type");
- valueList.add(rel.getRowType());
- }
-
- // Relational expressions which contain a program should report their
- // children in a different way than getChildExps().
- assert rel.getChildExps().length == 0;
- pw.explain(rel, termList, valueList);
+ public RelOptPlanWriter explainCalc(RelOptPlanWriter pw) {
+ return collectExplainTerms("", pw, pw.getDetailLevel());
}
- public void collectExplainTerms(
+ public RelOptPlanWriter collectExplainTerms(
String prefix,
- List<String> termList,
- List<Object> valueList)
+ RelOptPlanWriter pw)
{
- collectExplainTerms(
+ return collectExplainTerms(
prefix,
- termList,
- valueList,
+ pw,
SqlExplainLevel.EXPPLAN_ATTRIBUTES);
}
@@ -300,27 +272,23 @@ public void collectExplainTerms(
*
* @param prefix Prefix for term names, usually the empty string, but useful
* if a relational expression contains more than one program
- * @param termList Output list of terms
- * @param valueList Output list of expressions
+ * @param pw Plan writer
*/
- public void collectExplainTerms(
+ public RelOptPlanWriter collectExplainTerms(
String prefix,
- List<String> termList,
- List<Object> valueList,
+ RelOptPlanWriter pw,
SqlExplainLevel level)
{
final RelDataTypeField [] inFields = inputRowType.getFields();
final RelDataTypeField [] outFields = outputRowType.getFields();
assert outFields.length == projects.length : "outFields.length="
+ outFields.length
+ ", projects.length=" + projects.length;
- termList.add(
- prefix + "expr#0"
- + ((inFields.length > 1) ? (".." + (inFields.length - 1)) : ""));
- valueList.add("{inputs}");
+ pw.item(
+ prefix + "expr#0" + ((inFields.length > 1) ? (".." + (
+ inFields.length - 1)) : ""), "{inputs}");
for (int i = inFields.length; i < exprs.length; i++) {
- termList.add(prefix + "expr#" + i);
- valueList.add(exprs[i]);
+ pw.item(prefix + "expr#" + i, exprs[i]);
}
// If a lot of the fields are simply projections of the underlying
@@ -340,21 +308,19 @@ public void collectExplainTerms(
trivialCount = 0;
break;
default:
- termList.add(prefix + "proj#0.." + (trivialCount - 1));
- valueList.add("{exprs}");
+ pw.item(prefix + "proj#0.." + (trivialCount - 1), "{exprs}");
break;
}
// Print the non-trivial fields with their names as they appear in the
// output row type.
for (int i = trivialCount; i < projects.length; i++) {
- termList.add(prefix + outFields[i].getName());
- valueList.add(projects[i]);
+ pw.item(prefix + outFields[i].getName(), projects[i]);
}
if (condition != null) {
- termList.add(prefix + "$condition");
- valueList.add(condition);
+ pw.item(prefix + "$condition", condition);
}
+ return pw;
}
/**
View
8 src/test/java/org/eigenbase/relopt/volcano/VolcanoPlannerTest.java
@@ -479,12 +479,10 @@ protected RelDataType deriveRowType()
new String[] { "this" });
}
- public void explain(RelOptPlanWriter pw)
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw)
{
- pw.explain(
- this,
- new String[] { "label" },
- new Object[] { label });
+ return super.explainTerms(pw)
+ .item("label", label);
}
}
View
9 src/test/java/org/eigenbase/relopt/volcano/VolcanoPlannerTraitTest.java
@@ -368,12 +368,9 @@ protected RelDataType deriveRowType()
new String[] { "this" });
}
- public void explain(RelOptPlanWriter pw)
- {
- pw.explain(
- this,
- new String[] { "label" },
- new Object[] { label });
+ public RelOptPlanWriter explainTerms(RelOptPlanWriter pw) {
+ return super.explainTerms(pw)
+ .item("label", label);
}
}

0 comments on commit 4737cbb

Please sign in to comment.
Something went wrong with that request. Please try again.