From e6154a9f82a4bef438a1e15d61fc2b5bafa266e9 Mon Sep 17 00:00:00 2001 From: datomo Date: Mon, 9 Dec 2024 16:29:06 +0100 Subject: [PATCH] adjustment to make rowCount calculation more robust and hopefully fixing null error for polyAlg tests --- .../polypheny/db/algebra/AbstractAlgNode.java | 16 ++++--- .../db/algebra/convert/ConverterImpl.java | 12 +++-- .../polypheny/db/algebra/core/Aggregate.java | 8 +++- .../org/polypheny/db/algebra/core/Calc.java | 4 +- .../polypheny/db/algebra/core/Correlate.java | 15 ++++-- .../polypheny/db/algebra/core/Exchange.java | 8 +++- .../org/polypheny/db/algebra/core/Filter.java | 10 ++-- .../org/polypheny/db/algebra/core/Join.java | 8 +++- .../polypheny/db/algebra/core/Project.java | 10 ++-- .../db/algebra/core/RelTableFunctionScan.java | 16 ++----- .../org/polypheny/db/algebra/core/Sort.java | 10 ++-- .../org/polypheny/db/algebra/core/Values.java | 8 +++- .../org/polypheny/db/algebra/core/Window.java | 8 +++- .../db/algebra/core/relational/RelModify.java | 3 +- .../enumerable/EnumerableThetaJoin.java | 8 +++- .../metadata/AlgMdDistinctRowCount.java | 7 +-- .../metadata/AlgMdPercentageOriginalRows.java | 5 +- .../algebra/metadata/AlgMdPopulationSize.java | 6 ++- .../db/algebra/metadata/AlgMdSelectivity.java | 11 +++-- .../db/algebra/metadata/AlgMdTupleCount.java | 48 ++++++++----------- .../db/algebra/metadata/AlgMdUtil.java | 40 +++++++++------- .../db/algebra/metadata/AlgMetadataQuery.java | 7 --- .../algebra/rules/LoptOptimizeJoinRule.java | 12 ++--- .../algebra/rules/LoptSemiJoinOptimizer.java | 2 +- .../rules/MultiJoinOptimizeBushyRule.java | 4 +- .../polypheny/db/plan/hep/HepAlgVertex.java | 2 +- .../polypheny/db/plan/volcano/AlgSubset.java | 4 +- .../db/plan/volcano/VolcanoPlanner.java | 4 +- .../org/polypheny/db/util/BuiltInMethod.java | 2 +- .../db/routing/UiRoutingPageUtil.java | 32 +++++++------ .../db/polyalg/PolyAlgParsingTest.java | 9 +++- .../cottontail/algebra/CottontailSort.java | 2 +- .../polypheny/db/adapter/jdbc/JdbcRules.java | 11 +++-- 33 files changed, 199 insertions(+), 153 deletions(-) diff --git a/core/src/main/java/org/polypheny/db/algebra/AbstractAlgNode.java b/core/src/main/java/org/polypheny/db/algebra/AbstractAlgNode.java index 7f492a5db6..f1a721eea5 100644 --- a/core/src/main/java/org/polypheny/db/algebra/AbstractAlgNode.java +++ b/core/src/main/java/org/polypheny/db/algebra/AbstractAlgNode.java @@ -44,6 +44,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import lombok.Getter; @@ -321,8 +322,12 @@ public AlgNode accept( RexShuttle shuttle ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // by default, assume cost is proportional to number of rows - double tupleCount = mq.getTupleCount( this ); - return planner.getCostFactory().makeCost( tupleCount, tupleCount, 0 ); + Optional tupleCount = mq.getTupleCount( this ); + if ( tupleCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } + + return planner.getCostFactory().makeCost( tupleCount.get(), tupleCount.get(), 0 ); } @@ -456,10 +461,9 @@ private ObjectNode serializeMetadata( ObjectMapper mapper, GlobalStats gs ) { } PolyAlgMetadata meta = new PolyAlgMetadata( mapper, gs ); AlgMetadataQuery mq = this.getCluster().getMetadataQuery(); - try { - meta.addCosts( mq.getNonCumulativeCost( this ), mq.getCumulativeCost( this ), mq.getTupleCount( this ) ); - } catch ( Exception ignored ) { - } + + mq.getTupleCount( this ).ifPresent( aDouble -> meta.addCosts( mq.getNonCumulativeCost( this ), mq.getCumulativeCost( this ), aDouble ) ); + return meta.serialize(); } diff --git a/core/src/main/java/org/polypheny/db/algebra/convert/ConverterImpl.java b/core/src/main/java/org/polypheny/db/algebra/convert/ConverterImpl.java index 6f8a9f1e94..49feed2919 100644 --- a/core/src/main/java/org/polypheny/db/algebra/convert/ConverterImpl.java +++ b/core/src/main/java/org/polypheny/db/algebra/convert/ConverterImpl.java @@ -42,6 +42,7 @@ import org.polypheny.db.plan.AlgPlanner; import org.polypheny.db.plan.AlgTraitDef; import org.polypheny.db.plan.AlgTraitSet; +import java.util.Optional; /** @@ -70,12 +71,13 @@ protected ConverterImpl( AlgCluster cluster, AlgTraitDef traitDef, AlgTraitSe @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - Double dRows = mq.getTupleCount( getInput() ); - if ( dRows == null ) { - dRows = Double.MAX_VALUE; - } + Optional dRows = mq.getTupleCount( getInput() ); double dIo = 0; - return planner.getCostFactory().makeCost( dRows, dRows, dIo ); + if ( dRows.isEmpty() ) { + return planner.getCostFactory().makeCost( Double.MAX_VALUE, Double.MAX_VALUE, dIo ); + } + + return planner.getCostFactory().makeCost( dRows.get(), dRows.get(), dIo ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Aggregate.java b/core/src/main/java/org/polypheny/db/algebra/core/Aggregate.java index 71a868aa16..01cdb8d914 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Aggregate.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Aggregate.java @@ -40,6 +40,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import lombok.Getter; @@ -281,7 +282,10 @@ public double estimateTupleCount( AlgMetadataQuery mq ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // REVIEW jvs: This is bogus, but no more bogus than what's currently in Join. - double rowCount = mq.getTupleCount( this ); + Optional rowCount = mq.getTupleCount( this ); + if ( rowCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } // Aggregates with more aggregate functions cost a bit more float multiplier = 1f + (float) aggCalls.size() * 0.125f; for ( AggregateCall aggCall : aggCalls ) { @@ -290,7 +294,7 @@ public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { multiplier += 0.0125f; } } - return planner.getCostFactory().makeCost( rowCount * multiplier, 0, 0 ); + return planner.getCostFactory().makeCost( rowCount.get() * multiplier, 0, 0 ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Calc.java b/core/src/main/java/org/polypheny/db/algebra/core/Calc.java index 12fd07908f..a29b91aed8 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Calc.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Calc.java @@ -126,8 +126,8 @@ public double estimateTupleCount( AlgMetadataQuery mq ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double dRows = mq.getTupleCount( this ); - double dCpu = mq.getTupleCount( getInput() ) * program.getExprCount(); + double dRows = mq.getTupleCount( this ).orElse( Double.MAX_VALUE ); + double dCpu = mq.getTupleCount( getInput() ).orElse( Double.MAX_VALUE ) * program.getExprCount(); double dIo = 0; return planner.getCostFactory().makeCost( dRows, dCpu, dIo ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Correlate.java b/core/src/main/java/org/polypheny/db/algebra/core/Correlate.java index 6710ad4081..0fde1f3fe0 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Correlate.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Correlate.java @@ -36,6 +36,7 @@ import com.google.common.collect.ImmutableSet; import java.util.List; +import java.util.Optional; import lombok.Getter; import org.polypheny.db.algebra.AlgNode; import org.polypheny.db.algebra.AlgWriter; @@ -158,7 +159,10 @@ public ImmutableSet getVariablesSet() { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double rowCount = mq.getTupleCount( this ); + Optional rowCount = mq.getTupleCount( this ); + if ( rowCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } final double rightRowCount = right.estimateTupleCount( mq ); final double leftRowCount = left.estimateTupleCount( mq ); @@ -166,13 +170,16 @@ public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { return planner.getCostFactory().makeInfiniteCost(); } - Double restartCount = mq.getTupleCount( getLeft() ); + Optional restartCount = mq.getTupleCount( getLeft() ); + if ( restartCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } // RelMetadataQuery.getCumulativeCost(getRight()); does not work for // RelSubset, so we ask planner to cost-estimate right relation AlgOptCost rightCost = planner.getCost( getRight(), mq ); - AlgOptCost rescanCost = rightCost.multiplyBy( Math.max( 1.0, restartCount - 1 ) ); + AlgOptCost rescanCost = rightCost.multiplyBy( Math.max( 1.0, restartCount.get() - 1 ) ); - return planner.getCostFactory().makeCost( rowCount /* generate results */ + leftRowCount /* relScan left results */, 0, 0 ).plus( rescanCost ); + return planner.getCostFactory().makeCost( rowCount.get() /* generate results */ + leftRowCount /* relScan left results */, 0, 0 ).plus( rescanCost ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Exchange.java b/core/src/main/java/org/polypheny/db/algebra/core/Exchange.java index 0e00d85106..1cb155787a 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Exchange.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Exchange.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import org.polypheny.db.algebra.AlgDistribution; import org.polypheny.db.algebra.AlgDistributions; @@ -97,9 +98,12 @@ public AlgDistribution getDistribution() { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // Higher cost if rows are wider discourages pushing a project through an exchange. - double rowCount = mq.getTupleCount( this ); + Optional rowCount = mq.getTupleCount( this ); + if ( rowCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } double bytesPerRow = getTupleType().getFieldCount() * 4; - return planner.getCostFactory().makeCost( Util.nLogN( rowCount ) * bytesPerRow, rowCount, 0 ); + return planner.getCostFactory().makeCost( Util.nLogN( rowCount.get() ) * bytesPerRow, rowCount.get(), 0 ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Filter.java b/core/src/main/java/org/polypheny/db/algebra/core/Filter.java index 0d2089ce64..4dc7fd8129 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Filter.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Filter.java @@ -36,6 +36,7 @@ import com.google.common.collect.ImmutableList; import java.util.List; +import java.util.Optional; import lombok.Getter; import org.polypheny.db.algebra.AlgNode; import org.polypheny.db.algebra.AlgWriter; @@ -130,10 +131,13 @@ public boolean isValid( Litmus litmus, Context context ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double dRows = mq.getTupleCount( this ); - double dCpu = mq.getTupleCount( getInput() ); + Optional dRows = mq.getTupleCount( this ); + Optional dCpu = mq.getTupleCount( getInput() ); double dIo = 0; - return planner.getCostFactory().makeCost( dRows, dCpu, dIo ); + if(dRows.isEmpty() || dCpu.isEmpty()) { + return planner.getCostFactory().makeInfiniteCost(); + } + return planner.getCostFactory().makeCost( dRows.get(), dCpu.get(), dIo ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Join.java b/core/src/main/java/org/polypheny/db/algebra/core/Join.java index 6289a3d94d..8f3b957a6b 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Join.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Join.java @@ -39,6 +39,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import lombok.Getter; import org.polypheny.db.algebra.AlgNode; @@ -162,8 +163,11 @@ public boolean isValid( Litmus litmus, Context context ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // REVIEW jvs: Just for now... - double rowCount = mq.getTupleCount( this ); - return planner.getCostFactory().makeCost( rowCount, 0, 0 ); + Optional rowCount = mq.getTupleCount( this ); + if ( rowCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } + return planner.getCostFactory().makeCost( rowCount.get(), 0, 0 ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Project.java b/core/src/main/java/org/polypheny/db/algebra/core/Project.java index 67c6a31f4f..98e1f0ebc3 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Project.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Project.java @@ -38,6 +38,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.calcite.linq4j.Ord; @@ -180,10 +181,13 @@ public boolean isValid( Litmus litmus, Context context ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double dRows = mq.getTupleCount( getInput() ); - double dCpu = dRows * exps.size(); + Optional dRows = mq.getTupleCount( getInput() ); + if ( dRows.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } + double dCpu = dRows.get() * exps.size(); double dIo = 0; - return planner.getCostFactory().makeCost( dRows, dCpu, dIo ); + return planner.getCostFactory().makeCost( dRows.get(), dCpu, dIo ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/RelTableFunctionScan.java b/core/src/main/java/org/polypheny/db/algebra/core/RelTableFunctionScan.java index 3043575a1e..769f4a4bb1 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/RelTableFunctionScan.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/RelTableFunctionScan.java @@ -39,6 +39,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.calcite.linq4j.Ord; @@ -58,7 +59,7 @@ /** * Relational expression that calls a table-valued function. - * + *

* The function returns a result set. * It can appear as a leaf in a query tree, or can be applied to relational inputs. * @@ -151,23 +152,16 @@ public double estimateTupleCount( AlgMetadataQuery mq ) { // Calculate result as the sum of the input row count estimates, assuming there are any, otherwise use the superclass default. So for a no-input UDX, behave like an AbstractAlgNode; // for a one-input UDX, behave like a SingleRel; for a multi-input UDX, behave like UNION ALL. // TODO jvs 10-Sep-2007: UDX-supplied costing metadata. - if ( inputs.size() == 0 ) { + if ( inputs.isEmpty() ) { return super.estimateTupleCount( mq ); } - double nRows = 0.0; - for ( AlgNode input : inputs ) { - Double d = mq.getTupleCount( input ); - if ( d != null ) { - nRows += d; - } - } - return nRows; + return inputs.stream().map( mq::getTupleCount ).filter( Optional::isPresent ).mapToDouble( Optional::get ).sum(); // todo maybe only use the sum if all are not infinite } /** * Returns function invocation expression. - * + *

* Within this rexCall, instances of {@link RexIndexRef} refer to entire input {@link AlgNode}s rather than their fields. * * @return function invocation expression diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Sort.java b/core/src/main/java/org/polypheny/db/algebra/core/Sort.java index d218fb4abd..14c7f53319 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Sort.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Sort.java @@ -37,6 +37,7 @@ import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import lombok.Getter; import org.apache.calcite.linq4j.Ord; @@ -144,10 +145,13 @@ public final Sort copy( AlgTraitSet traitSet, List inputs ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // Higher cost if rows are wider discourages pushing a project through a sort. - final double rowCount = mq.getTupleCount( this ); + Optional rowCount = mq.getTupleCount( this ); + if ( rowCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } final double bytesPerRow = getTupleType().getFieldCount() * 4; - final double cpu = Util.nLogN( rowCount ) * bytesPerRow; - return planner.getCostFactory().makeCost( rowCount, cpu, 0 ); + final double cpu = Util.nLogN( rowCount.get() ) * bytesPerRow; + return planner.getCostFactory().makeCost( rowCount.get(), cpu, 0 ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Values.java b/core/src/main/java/org/polypheny/db/algebra/core/Values.java index 1d180a3ab8..703d769505 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Values.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Values.java @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; import lombok.Getter; @@ -144,12 +145,15 @@ protected AlgDataType deriveRowType() { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double dRows = mq.getTupleCount( this ); + Optional dRows = mq.getTupleCount( this ); + if ( dRows.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } // Assume CPU is negligible since values are precomputed. double dCpu = 1; double dIo = 0; - return planner.getCostFactory().makeCost( dRows, dCpu, dIo ); + return planner.getCostFactory().makeCost( dRows.get(), dCpu, dIo ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/Window.java b/core/src/main/java/org/polypheny/db/algebra/core/Window.java index d5455128aa..1f4f383d88 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/Window.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/Window.java @@ -38,6 +38,7 @@ import java.util.AbstractList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import org.apache.calcite.linq4j.Ord; import org.polypheny.db.algebra.AlgCollation; @@ -207,12 +208,15 @@ public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // // TODO #1. Add memory cost. // TODO #2. MIN and MAX have higher CPU cost than SUM and COUNT. - final double rowsIn = mq.getTupleCount( getInput() ); + Optional rowsIn = mq.getTupleCount( getInput() ); + if ( rowsIn.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } int count = groups.size(); for ( Group group : groups ) { count += group.aggCalls.size(); } - return planner.getCostFactory().makeCost( rowsIn, rowsIn * count, 0 ); + return planner.getCostFactory().makeCost( rowsIn.get(), rowsIn.get() * count, 0 ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/core/relational/RelModify.java b/core/src/main/java/org/polypheny/db/algebra/core/relational/RelModify.java index 08053b2b51..113db85e06 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/relational/RelModify.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/relational/RelModify.java @@ -187,8 +187,7 @@ public AlgWriter explainTerms( AlgWriter pw ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // REVIEW jvs: Just for now... - double rowCount = mq.getTupleCount( this ); - return planner.getCostFactory().makeCost( rowCount, 0, 0 ); + return mq.getTupleCount( this ).map( count -> planner.getCostFactory().makeCost( count, 0, 0 ) ).orElse( planner.getCostFactory().makeInfiniteCost() ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/enumerable/EnumerableThetaJoin.java b/core/src/main/java/org/polypheny/db/algebra/enumerable/EnumerableThetaJoin.java index b866e72c0c..ae57b14e68 100644 --- a/core/src/main/java/org/polypheny/db/algebra/enumerable/EnumerableThetaJoin.java +++ b/core/src/main/java/org/polypheny/db/algebra/enumerable/EnumerableThetaJoin.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableList; +import java.util.Optional; import java.util.Set; import org.apache.calcite.linq4j.tree.BlockBuilder; import org.apache.calcite.linq4j.tree.Expression; @@ -96,7 +97,12 @@ public static EnumerableThetaJoin create( AlgNode left, AlgNode right, RexNode c @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double rowCount = mq.getTupleCount( this ); + Optional count = mq.getTupleCount( this ); + if ( count.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } + + double rowCount = count.get(); // Joins can be flipped, and for many algorithms, both versions are viable and have the same cost. To make the results stable between versions of the planner, // make one of the versions slightly more expensive. diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdDistinctRowCount.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdDistinctRowCount.java index adcb1b066d..b82aa5cf3c 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdDistinctRowCount.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdDistinctRowCount.java @@ -80,16 +80,17 @@ public MetadataDef getDef() { * * @see AlgMetadataQuery#getDistinctRowCount(AlgNode, ImmutableBitSet, RexNode) */ + @SuppressWarnings("unused")//used by codegen public Double getDistinctRowCount( AlgNode alg, AlgMetadataQuery mq, ImmutableBitSet groupKey, RexNode predicate ) { // REVIEW zfong: Broadbase code does not take into consideration selectivity of predicates passed in. Also, they assume the rows are unique even if the table is not boolean uniq = AlgMdUtil.areColumnsDefinitelyUnique( mq, alg, groupKey ); if ( uniq ) { - return NumberUtil.multiply( mq.getTupleCount( alg ), mq.getSelectivity( alg, predicate ) ); + return NumberUtil.multiply( mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ), mq.getSelectivity( alg, predicate ) ); } return null; } - + @SuppressWarnings("unused")//used by codegen public Double getDistinctRowCount( Union alg, AlgMetadataQuery mq, ImmutableBitSet groupKey, RexNode predicate ) { double rowCount = 0.0; int[] adjustments = new int[alg.getTupleType().getFieldCount()]; @@ -258,7 +259,7 @@ public Double getDistinctRowCount( Project alg, AlgMetadataQuery mq, ImmutableBi distinctRowCount *= subRowCount; } - return AlgMdUtil.numDistinctVals( distinctRowCount, mq.getTupleCount( alg ) ); + return AlgMdUtil.numDistinctVals( distinctRowCount, mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ) ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPercentageOriginalRows.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPercentageOriginalRows.java index cfd8271ad7..7ce17579c5 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPercentageOriginalRows.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPercentageOriginalRows.java @@ -89,7 +89,7 @@ public Double getPercentageOriginalRows( Union alg, AlgMetadataQuery mq ) { // case where a huge table has been completely filtered away. for ( AlgNode input : alg.getInputs() ) { - double rowCount = mq.getTupleCount( input ); + double rowCount = mq.getTupleCount( input ).orElse( Double.MAX_VALUE ); double percentage = mq.getPercentageOriginalRows( input ); if ( percentage != 0.0 ) { denominator += rowCount / percentage; @@ -135,8 +135,7 @@ public Double getPercentageOriginalRows( AlgNode alg, AlgMetadataQuery mq ) { } // Compute product of percentage filtering from this alg (assuming any filtering is the effect of single-table filters) with the percentage filtering performed by the child. - Double algPercentage = - quotientForPercentage( mq.getTupleCount( alg ), mq.getTupleCount( child ) ); + Double algPercentage = quotientForPercentage( mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ), mq.getTupleCount( child ).orElse( Double.MAX_VALUE ) ); if ( algPercentage == null ) { return null; } diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPopulationSize.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPopulationSize.java index 149b382c8b..4e6839fc0d 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPopulationSize.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdPopulationSize.java @@ -122,6 +122,7 @@ public Double getPopulationSize( Values alg, AlgMetadataQuery mq, ImmutableBitSe } + @SuppressWarnings("unused") // used by codegen public Double getPopulationSize( Project alg, AlgMetadataQuery mq, ImmutableBitSet groupKey ) { ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder(); ImmutableBitSet.Builder projCols = ImmutableBitSet.builder(); @@ -147,7 +148,7 @@ public Double getPopulationSize( Project alg, AlgMetadataQuery mq, ImmutableBitS } // REVIEW zfong: Broadbase did not have the call to numDistinctVals. This is needed; otherwise, population can be larger than the number of rows in the AlgNode. - return AlgMdUtil.numDistinctVals( population, mq.getTupleCount( alg ) ); + return AlgMdUtil.numDistinctVals( population, mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ) ); } @@ -156,13 +157,14 @@ public Double getPopulationSize( Project alg, AlgMetadataQuery mq, ImmutableBitS * * @see AlgMetadataQuery#getPopulationSize(AlgNode, ImmutableBitSet) */ + @SuppressWarnings("unused") //used by codegen public Double getPopulationSize( AlgNode alg, AlgMetadataQuery mq, ImmutableBitSet groupKey ) { // if the keys are unique, return the row count; otherwise, we have no further information on which to return any legitimate value // REVIEW zfong: Broadbase code returns the product of each unique key, which would result in the population being larger than the total rows in the relnode boolean uniq = AlgMdUtil.areColumnsDefinitelyUnique( mq, alg, groupKey ); if ( uniq ) { - return mq.getTupleCount( alg ); + return mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ); } return null; diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdSelectivity.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdSelectivity.java index eafd7c1146..32900f958f 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdSelectivity.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdSelectivity.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.polypheny.db.algebra.AlgNode; import org.polypheny.db.algebra.core.Aggregate; import org.polypheny.db.algebra.core.Filter; @@ -72,7 +73,7 @@ public MetadataDef getDef() { public Double getSelectivity( Union alg, AlgMetadataQuery mq, RexNode predicate ) { - if ( (alg.getInputs().size() == 0) || (predicate == null) ) { + if ( (alg.getInputs().isEmpty()) || (predicate == null) ) { return 1.0; } @@ -81,8 +82,8 @@ public Double getSelectivity( Union alg, AlgMetadataQuery mq, RexNode predicate int[] adjustments = new int[alg.getTupleType().getFieldCount()]; RexBuilder rexBuilder = alg.getCluster().getRexBuilder(); for ( AlgNode input : alg.getInputs() ) { - Double nRows = mq.getTupleCount( input ); - if ( nRows == null ) { + Optional nRows = mq.getTupleCount( input ); + if ( nRows.isEmpty() ) { return null; } @@ -90,8 +91,8 @@ public Double getSelectivity( Union alg, AlgMetadataQuery mq, RexNode predicate RexNode modifiedPred = predicate.accept( new AlgOptUtil.RexInputConverter( rexBuilder, null, input.getTupleType().getFields(), adjustments ) ); double sel = mq.getSelectivity( input, modifiedPred ); - sumRows += nRows; - sumSelectedRows += nRows * sel; + sumRows += nRows.get(); + sumSelectedRows += nRows.get() * sel; } if ( sumRows < 1.0 ) { diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdTupleCount.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdTupleCount.java index 4564d40f00..e528cc0c07 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdTupleCount.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdTupleCount.java @@ -59,6 +59,7 @@ import org.polypheny.db.util.ImmutableBitSet; import org.polypheny.db.util.NumberUtil; import org.polypheny.db.util.Util; +import java.util.Optional; /** @@ -87,44 +88,30 @@ public Double getTupleCount( AlgNode alg, AlgMetadataQuery mq ) { public Double getTupleCount( AlgSubset subset, AlgMetadataQuery mq ) { - return mq.getTupleCount( Util.first( subset.getBest(), subset.getOriginal() ) ); + return mq.getTupleCount( Util.first( subset.getBest(), subset.getOriginal() ) ).orElse( Double.MAX_VALUE ); } public Double getTupleCount( Union alg, AlgMetadataQuery mq ) { double rowCount = 0.0; for ( AlgNode input : alg.getInputs() ) { - Double partialRowCount = mq.getTupleCount( input ); - if ( partialRowCount == null ) { + Optional partialRowCount = mq.getTupleCount( input ); + if ( partialRowCount.isEmpty() ) { return null; } - rowCount += partialRowCount; + rowCount += partialRowCount.get(); } return rowCount; } public Double getTupleCount( Intersect alg, AlgMetadataQuery mq ) { - Double rowCount = null; - for ( AlgNode input : alg.getInputs() ) { - Double partialRowCount = mq.getTupleCount( input ); - if ( rowCount == null || partialRowCount != null && partialRowCount < rowCount ) { - rowCount = partialRowCount; - } - } - return rowCount; + return alg.getInputs().stream().map( mq::getTupleCount ).filter( Optional::isPresent ).map( Optional::get ).reduce( null, ( a, b ) -> a != null ? Double.min( a, b ) : b ); } public Double getTupleCount( Minus alg, AlgMetadataQuery mq ) { - Double rowCount = null; - for ( AlgNode input : alg.getInputs() ) { - Double partialRowCount = mq.getTupleCount( input ); - if ( rowCount == null || partialRowCount != null && partialRowCount < rowCount ) { - rowCount = partialRowCount; - } - } - return rowCount; + return alg.getInputs().stream().map( mq::getTupleCount ).filter( Optional::isPresent ).map( Optional::get ).reduce( null, ( a, b ) -> a != null ? Double.min( a, b ) : b ); } @@ -139,15 +126,16 @@ public Double getTupleCount( Calc alg, AlgMetadataQuery mq ) { public Double getTupleCount( Project alg, AlgMetadataQuery mq ) { - return mq.getTupleCount( alg.getInput() ); + return mq.getTupleCount( alg.getInput() ).orElse( Double.MAX_VALUE ); } public Double getTupleCount( Sort alg, AlgMetadataQuery mq ) { - Double rowCount = mq.getTupleCount( alg.getInput() ); - if ( rowCount == null ) { + Optional count = mq.getTupleCount( alg.getInput() ); + if ( count.isEmpty()) { return null; } + double rowCount = count.get(); if ( alg.offset instanceof RexDynamicParam ) { return rowCount; } @@ -168,10 +156,12 @@ public Double getTupleCount( Sort alg, AlgMetadataQuery mq ) { public Double getTupleCount( EnumerableLimit alg, AlgMetadataQuery mq ) { - Double rowCount = mq.getTupleCount( alg.getInput() ); - if ( rowCount == null ) { + Optional count = mq.getTupleCount( alg.getInput() ); + if ( count.isEmpty() ) { return null; } + double rowCount = count.get(); + if ( alg.offset instanceof RexDynamicParam ) { return rowCount; } @@ -193,7 +183,7 @@ public Double getTupleCount( EnumerableLimit alg, AlgMetadataQuery mq ) { // Covers Converter, Interpreter public Double getTupleCount( SingleAlg alg, AlgMetadataQuery mq ) { - return mq.getTupleCount( alg.getInput() ); + return mq.getTupleCount( alg.getInput() ).orElse( Double.MAX_VALUE ); } @@ -208,7 +198,7 @@ public Double getTupleCount( SemiJoin alg, AlgMetadataQuery mq ) { return NumberUtil.multiply( mq.getSelectivity( alg.getLeft(), semiJoinSelectivity ), - mq.getTupleCount( alg.getLeft() ) ); + mq.getTupleCount( alg.getLeft() ).orElse( Double.MAX_VALUE ) ); } @@ -218,7 +208,7 @@ public Double getTupleCount( Aggregate alg, AlgMetadataQuery mq ) { // rowCount is the cardinality of the group by columns Double distinctRowCount = mq.getDistinctRowCount( alg.getInput(), groupKey, null ); if ( distinctRowCount == null ) { - distinctRowCount = mq.getTupleCount( alg.getInput() ) / 10; + distinctRowCount = mq.getTupleCount( alg.getInput() ).orElse( Double.MAX_VALUE ) / 10; } // Grouping sets multiply @@ -228,7 +218,7 @@ public Double getTupleCount( Aggregate alg, AlgMetadataQuery mq ) { } - public Double getTupleCount( RelScan alg, AlgMetadataQuery mq ) { + public Double getTupleCount( RelScan alg, AlgMetadataQuery mq ) { return alg.estimateTupleCount( mq ); } diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdUtil.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdUtil.java index ab069a8a05..448159ccc6 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdUtil.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMdUtil.java @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import org.polypheny.db.algebra.AlgCollation; import org.polypheny.db.algebra.AlgNode; @@ -489,7 +490,7 @@ public static Double getJoinPopulationSize( AlgMetadataQuery mq, AlgNode joinRel mq.getPopulationSize( left, leftMask.build() ), mq.getPopulationSize( right, rightMask.build() ) ); - return numDistinctVals( population, mq.getTupleCount( joinRel ) ); + return numDistinctVals( population, mq.getTupleCount( joinRel ).orElse( Double.MAX_VALUE ) ); } @@ -548,7 +549,7 @@ public static Double getJoinDistinctRowCount( AlgMetadataQuery mq, AlgNode joinR mq.getDistinctRowCount( right, rightMask.build(), rightPred ) ); } - return AlgMdUtil.numDistinctVals( distRowCount, mq.getTupleCount( joinRel ) ); + return AlgMdUtil.numDistinctVals( distRowCount, mq.getTupleCount( joinRel ).orElse( Double.MAX_VALUE ) ); } @@ -558,7 +559,7 @@ public static Double getJoinDistinctRowCount( AlgMetadataQuery mq, AlgNode joinR public static double getUnionAllRowCount( AlgMetadataQuery mq, Union alg ) { double rowCount = 0; for ( AlgNode input : alg.getInputs() ) { - rowCount += mq.getTupleCount( input ); + rowCount += mq.getTupleCount( input ).orElse( Double.MAX_VALUE ); } return rowCount; } @@ -570,9 +571,14 @@ public static double getUnionAllRowCount( AlgMetadataQuery mq, Union alg ) { public static double getMinusRowCount( AlgMetadataQuery mq, Minus minus ) { // REVIEW jvs: I just pulled this out of a hat. final List inputs = minus.getInputs(); - double dRows = mq.getTupleCount( inputs.get( 0 ) ); + Optional rows = mq.getTupleCount( inputs.get( 0 ) ); + if ( rows.isEmpty() ) { + return Double.MAX_VALUE; + } + + double dRows = 0; for ( int i = 1; i < inputs.size(); i++ ) { - dRows -= 0.5 * mq.getTupleCount( inputs.get( i ) ); + dRows -= 0.5 * mq.getTupleCount( inputs.get( i ) ).orElse( Double.MAX_VALUE ); } if ( dRows < 0 ) { dRows = 0; @@ -586,18 +592,18 @@ public static double getMinusRowCount( AlgMetadataQuery mq, Minus minus ) { */ public static Double getJoinRowCount( AlgMetadataQuery mq, Join join, RexNode condition ) { // Row count estimates of 0 will be rounded up to 1. So, use maxRowCount where the product is very small. - final Double left = mq.getTupleCount( join.getLeft() ); - final Double right = mq.getTupleCount( join.getRight() ); - if ( left == null || right == null ) { + Optional left = mq.getTupleCount( join.getLeft() ); + Optional right = mq.getTupleCount( join.getRight() ); + if ( left.isEmpty() || right.isEmpty() ) { return null; } - if ( left <= 1D || right <= 1D ) { + if ( left.get() <= 1D || right.get() <= 1D ) { Double max = mq.getMaxRowCount( join ); if ( max != null && max <= 1D ) { return max; } } - double product = left * right; + double product = left.get() * right.get(); // TODO: correlation factor return product * mq.getSelectivity( join, condition ); @@ -609,11 +615,11 @@ public static Double getJoinRowCount( AlgMetadataQuery mq, Join join, RexNode co */ public static Double getSemiJoinRowCount( AlgMetadataQuery mq, AlgNode left, AlgNode right, JoinAlgType joinType, RexNode condition ) { // TODO: correlation factor - final Double leftCount = mq.getTupleCount( left ); - if ( leftCount == null ) { + Optional leftCount = mq.getTupleCount( left ); + if ( leftCount.isEmpty() ) { return null; } - return leftCount * RexUtil.getSelectivity( condition ); + return leftCount.get() * RexUtil.getSelectivity( condition ); } @@ -631,7 +637,7 @@ public static double estimateFilteredRows( AlgNode child, RexProgram program, Al public static double estimateFilteredRows( AlgNode child, RexNode condition, AlgMetadataQuery mq ) { - return mq.getTupleCount( child ) * mq.getSelectivity( child, condition ); + return mq.getTupleCount( child ).map( count -> count * mq.getSelectivity( child, condition ) ).orElse( Double.MAX_VALUE ); } @@ -687,21 +693,21 @@ public Double visitIndexRef( RexIndexRef var ) { if ( distinctRowCount == null ) { return null; } else { - return numDistinctVals( distinctRowCount, mq.getTupleCount( alg ) ); + return numDistinctVals( distinctRowCount, mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ) ); } } @Override public Double visitLiteral( RexLiteral literal ) { - return numDistinctVals( 1.0, mq.getTupleCount( alg ) ); + return numDistinctVals( 1.0, mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ) ); } @Override public Double visitCall( RexCall call ) { Double distinctRowCount; - Double rowCount = mq.getTupleCount( alg ); + Double rowCount = mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ); if ( call.isA( Kind.MINUS_PREFIX ) ) { distinctRowCount = cardOfProjExpr( mq, alg, call.getOperands().get( 0 ) ); } else if ( call.isA( ImmutableList.of( Kind.PLUS, Kind.MINUS ) ) ) { diff --git a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMetadataQuery.java b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMetadataQuery.java index a7c61b654c..48ddd53435 100644 --- a/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMetadataQuery.java +++ b/core/src/main/java/org/polypheny/db/algebra/metadata/AlgMetadataQuery.java @@ -242,13 +242,6 @@ public Optional getTupleCount( AlgNode alg ) { } } - - @SuppressWarnings("unused") // used by codegen - public double getTupleCountOrMax( AlgNode alg ) { - return getTupleCount( alg ).orElse( Double.MAX_VALUE ); - } - - /** * Returns the {@link BuiltInMetadata.MaxRowCount#getMaxRowCount()} statistic. * diff --git a/core/src/main/java/org/polypheny/db/algebra/rules/LoptOptimizeJoinRule.java b/core/src/main/java/org/polypheny/db/algebra/rules/LoptOptimizeJoinRule.java index ee7d0e33ed..34c979b28c 100644 --- a/core/src/main/java/org/polypheny/db/algebra/rules/LoptOptimizeJoinRule.java +++ b/core/src/main/java/org/polypheny/db/algebra/rules/LoptOptimizeJoinRule.java @@ -42,6 +42,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeSet; import org.polypheny.db.algebra.AlgNode; @@ -1398,14 +1399,13 @@ private boolean swapInputs( AlgMetadataQuery mq, LoptMultiJoin multiJoin, LoptJo return !multiJoin.isLeftFactorInRemovableSelfJoin( ((LoptJoinTree.Leaf) left.getFactorTree()).getId() ); } - final Double leftRowCount = mq.getTupleCount( left.getJoinTree() ); - final Double rightRowCount = mq.getTupleCount( right.getJoinTree() ); + Optional leftRowCount = mq.getTupleCount( left.getJoinTree() ); + Optional rightRowCount = mq.getTupleCount( right.getJoinTree() ); // The left side is smaller than the right if it has fewer rows, or if it has the same number of rows as the right (excluding roundoff), but fewer columns. - if ( (leftRowCount != null) - && (rightRowCount != null) - && ((leftRowCount < rightRowCount) - || ((Math.abs( leftRowCount - rightRowCount ) + if ( (leftRowCount.isPresent()) && (rightRowCount.isPresent()) + && ((leftRowCount.get() < rightRowCount.get()) + || ((Math.abs( leftRowCount.get() - rightRowCount.get() ) < AlgOptUtil.EPSILON) && (rowWidthCost( left.getJoinTree() ) < rowWidthCost( right.getJoinTree() )))) ) { diff --git a/core/src/main/java/org/polypheny/db/algebra/rules/LoptSemiJoinOptimizer.java b/core/src/main/java/org/polypheny/db/algebra/rules/LoptSemiJoinOptimizer.java index 22e10fab74..b9d45c575d 100644 --- a/core/src/main/java/org/polypheny/db/algebra/rules/LoptSemiJoinOptimizer.java +++ b/core/src/main/java/org/polypheny/db/algebra/rules/LoptSemiJoinOptimizer.java @@ -531,7 +531,7 @@ private double computeScore( AlgNode factRel, AlgNode dimRel, SemiJoin semiJoin } // Compute the cost of doing an extra relScan on the dimension table, including the distinct sort on top of the relScan; if the dimension columns are already unique, no need to add on the dup removal cost. - final Double dimSortCost = mq.getTupleCount( dimRel ); + final Double dimSortCost = mq.getTupleCount( dimRel ).orElse( Double.MAX_VALUE ); final Double dupRemCost = uniq ? 0 : dimSortCost; final AlgOptCost dimCost = mq.getCumulativeCost( dimRel ); if ( (dimSortCost == null) || (dupRemCost == null) || (dimCost == null) ) { diff --git a/core/src/main/java/org/polypheny/db/algebra/rules/MultiJoinOptimizeBushyRule.java b/core/src/main/java/org/polypheny/db/algebra/rules/MultiJoinOptimizeBushyRule.java index 2fc2338e31..0a29b9b788 100644 --- a/core/src/main/java/org/polypheny/db/algebra/rules/MultiJoinOptimizeBushyRule.java +++ b/core/src/main/java/org/polypheny/db/algebra/rules/MultiJoinOptimizeBushyRule.java @@ -110,7 +110,7 @@ public void onMatch( AlgOptRuleCall call ) { int x = 0; for ( int i = 0; i < multiJoin.getNumJoinFactors(); i++ ) { final AlgNode alg = multiJoin.getJoinFactor( i ); - double cost = mq.getTupleCount( alg ); + double cost = mq.getTupleCount( alg ).orElse( Double.MAX_VALUE ); vertexes.add( new LeafVertex( i, alg, cost, x ) ); x += alg.getTupleType().getFieldCount(); } @@ -123,7 +123,7 @@ public void onMatch( AlgOptRuleCall call ) { // Comparator that chooses the best edge. A "good edge" is one that has a large difference in the number of rows on LHS and RHS. final Comparator edgeComparator = - new Comparator() { + new Comparator<>() { @Override public int compare( LoptMultiJoin.Edge e0, LoptMultiJoin.Edge e1 ) { return Double.compare( rowCountDiff( e0 ), rowCountDiff( e1 ) ); diff --git a/core/src/main/java/org/polypheny/db/plan/hep/HepAlgVertex.java b/core/src/main/java/org/polypheny/db/plan/hep/HepAlgVertex.java index 131a88694a..1d04718bc2 100644 --- a/core/src/main/java/org/polypheny/db/plan/hep/HepAlgVertex.java +++ b/core/src/main/java/org/polypheny/db/plan/hep/HepAlgVertex.java @@ -91,7 +91,7 @@ public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { @Override public double estimateTupleCount( AlgMetadataQuery mq ) { - return mq.getTupleCount( currentAlg ); + return mq.getTupleCount( currentAlg ).orElse( Double.MAX_VALUE ); } diff --git a/core/src/main/java/org/polypheny/db/plan/volcano/AlgSubset.java b/core/src/main/java/org/polypheny/db/plan/volcano/AlgSubset.java index eed119c71e..792a33eec9 100644 --- a/core/src/main/java/org/polypheny/db/plan/volcano/AlgSubset.java +++ b/core/src/main/java/org/polypheny/db/plan/volcano/AlgSubset.java @@ -194,9 +194,9 @@ public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { @Override public double estimateTupleCount( AlgMetadataQuery mq ) { if ( best != null ) { - return mq.getTupleCount( best ); + return mq.getTupleCount( best ).orElse( Double.MAX_VALUE ); } else { - return mq.getTupleCount( set.alg ); + return mq.getTupleCount( set.alg ).orElse( Double.MAX_VALUE ); } } diff --git a/core/src/main/java/org/polypheny/db/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/polypheny/db/plan/volcano/VolcanoPlanner.java index e9f1919dda..e7eac4b567 100644 --- a/core/src/main/java/org/polypheny/db/plan/volcano/VolcanoPlanner.java +++ b/core/src/main/java/org/polypheny/db/plan/volcano/VolcanoPlanner.java @@ -1089,7 +1089,7 @@ public void dump( PrintWriter pw ) { pw.print( ", importance=" + importance ); } AlgMetadataQuery mq = alg.getCluster().getMetadataQuery(); - pw.print( ", rowcount=" + mq.getTupleCount( alg ) ); + pw.print( ", rowcount=" + mq.getTupleCount( alg ).map( Object::toString ).orElse( "INFINITY" ) ); pw.println( ", cumulative cost=" + getCost( alg, mq ) ); } } @@ -1100,7 +1100,7 @@ public void dump( PrintWriter pw ) { /** * Re-computes the digest of a {@link AlgNode}. - * + *

* Since an algebra expression's digest contains the identifiers of its children, this method needs to be called * when the child has been renamed, for example if the child's set merges with another. * diff --git a/core/src/main/java/org/polypheny/db/util/BuiltInMethod.java b/core/src/main/java/org/polypheny/db/util/BuiltInMethod.java index 45bc6ae5fc..ad98b921e3 100644 --- a/core/src/main/java/org/polypheny/db/util/BuiltInMethod.java +++ b/core/src/main/java/org/polypheny/db/util/BuiltInMethod.java @@ -396,7 +396,7 @@ public enum BuiltInMethod { COLLATIONS( Collation.class, "collations" ), DISTRIBUTION( Distribution.class, "distribution" ), NODE_TYPES( NodeTypes.class, "getNodeTypes" ), - TUPLE_COUNT( TupleCount.class, "getTupleCountOrMax" ), + TUPLE_COUNT( TupleCount.class, "getTupleCount" ), MAX_ROW_COUNT( MaxRowCount.class, "getMaxRowCount" ), MIN_ROW_COUNT( MinRowCount.class, "getMinRowCount" ), DISTINCT_ROW_COUNT( DistinctRowCount.class, "getDistinctRowCount", ImmutableBitSet.class, RexNode.class ), diff --git a/dbms/src/main/java/org/polypheny/db/routing/UiRoutingPageUtil.java b/dbms/src/main/java/org/polypheny/db/routing/UiRoutingPageUtil.java index a9f9fd00d0..21604a8922 100644 --- a/dbms/src/main/java/org/polypheny/db/routing/UiRoutingPageUtil.java +++ b/dbms/src/main/java/org/polypheny/db/routing/UiRoutingPageUtil.java @@ -16,6 +16,7 @@ package org.polypheny.db.routing; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableList; @@ -72,25 +73,26 @@ private static void addRoutedPolyPlanPage( AlgNode routedNode, InformationManage ObjectMapper objectMapper = new ObjectMapper(); GlobalStats gs = GlobalStats.computeGlobalStats( routedNode ); String prefix = isPhysical ? "Physical" : "Routed"; - try { - ObjectNode objectNode = routedNode.serializePolyAlgebra( objectMapper, gs ); - String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString( objectNode ); - - InformationPage page = new InformationPage( prefix + " Query Plan" ).setStmtLabel( stmtIdx ); - page.fullWidth(); - InformationGroup group = new InformationGroup( page, prefix + " Query Plan" ); - queryAnalyzer.addPage( page ); - queryAnalyzer.addGroup( group ); - InformationPolyAlg infoPolyAlg = new InformationPolyAlg( group, jsonString, isPhysical ? PlanType.PHYSICAL : PlanType.ALLOCATION ); - if ( attachTextualPlan ) { - infoPolyAlg.setTextualPolyAlg( routedNode.buildPolyAlgebra( (String) null ) ); - } - queryAnalyzer.registerInformation( infoPolyAlg ); - } catch ( Exception e ) { + ObjectNode objectNode = routedNode.serializePolyAlgebra( objectMapper, gs ); + String jsonString; + try { + jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString( objectNode ); + }catch ( JsonProcessingException e ){ throw new GenericRuntimeException( e ); } + + InformationPage page = new InformationPage( prefix + " Query Plan" ).setStmtLabel( stmtIdx ); + page.fullWidth(); + InformationGroup group = new InformationGroup( page, prefix + " Query Plan" ); + queryAnalyzer.addPage( page ); + queryAnalyzer.addGroup( group ); + InformationPolyAlg infoPolyAlg = new InformationPolyAlg( group, jsonString, isPhysical ? PlanType.PHYSICAL : PlanType.ALLOCATION ); + if ( attachTextualPlan ) { + infoPolyAlg.setTextualPolyAlg( routedNode.buildPolyAlgebra( (String) null ) ); + } + queryAnalyzer.registerInformation( infoPolyAlg ); } diff --git a/dbms/src/test/java/org/polypheny/db/polyalg/PolyAlgParsingTest.java b/dbms/src/test/java/org/polypheny/db/polyalg/PolyAlgParsingTest.java index 0878bd7530..762eae2160 100644 --- a/dbms/src/test/java/org/polypheny/db/polyalg/PolyAlgParsingTest.java +++ b/dbms/src/test/java/org/polypheny/db/polyalg/PolyAlgParsingTest.java @@ -28,9 +28,11 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.polypheny.db.ResultIterator; import org.polypheny.db.TestHelper; import org.polypheny.db.TestHelper.JdbcConnection; import org.polypheny.db.algebra.AlgNode; @@ -46,6 +48,7 @@ import org.polypheny.db.algebra.polyalg.parser.nodes.PolyAlgNode; import org.polypheny.db.algebra.type.AlgDataTypeFactory; import org.polypheny.db.catalog.Catalog; +import org.polypheny.db.catalog.exceptions.GenericRuntimeException; import org.polypheny.db.catalog.logistic.DataModel; import org.polypheny.db.catalog.snapshot.Snapshot; import org.polypheny.db.cypher.CypherTestTemplate; @@ -257,8 +260,10 @@ private static String getResultAsString( List executedContexts, ExecutedContext context = executedContexts.get( 0 ); assertTrue( context.getException().isEmpty() || context.getException().get().getClass() == CyclicMetadataException.class, "Query resulted in an exception" ); - List> rows = context.getIterator().getAllRowsAndClose(); - String tupleType = context.getIterator().getImplementation().tupleType.toString(); + @NotNull ResultIterator iter = context.getIterator(); + String tupleType = context.getImplementation().tupleType.toString(); + List> rows = iter.getAllRowsAndClose(); + StringBuilder sb = new StringBuilder( tupleType ); for ( List row : rows ) { diff --git a/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/algebra/CottontailSort.java b/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/algebra/CottontailSort.java index 7fa567c104..f15ba624d0 100644 --- a/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/algebra/CottontailSort.java +++ b/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/algebra/CottontailSort.java @@ -58,7 +58,7 @@ public CottontailSort( AlgCluster cluster, AlgTraitSet traits, AlgNode child, Al @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - final double rowCount = mq.getTupleCount( this ) + 0.01; + final double rowCount = mq.getTupleCount( this ).orElse( Double.MAX_VALUE ) + 0.01; return planner.getCostFactory().makeCost( rowCount, 0, 0 ); } diff --git a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/JdbcRules.java b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/JdbcRules.java index f034471b4e..3f7e94cbf6 100644 --- a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/JdbcRules.java +++ b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/JdbcRules.java @@ -359,9 +359,12 @@ public JdbcJoin copy( AlgTraitSet traitSet, RexNode condition, AlgNode left, Alg @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { // We always "build" the - double rowCount = mq.getTupleCount( this ); + Optional rowCount = mq.getTupleCount( this ); + if ( rowCount.isEmpty() ) { + return planner.getCostFactory().makeInfiniteCost(); + } - return planner.getCostFactory().makeCost( rowCount, 0, 0 ); + return planner.getCostFactory().makeCost( rowCount.get(), 0, 0 ); } @@ -451,8 +454,8 @@ public double estimateTupleCount( AlgMetadataQuery mq ) { @Override public AlgOptCost computeSelfCost( AlgPlanner planner, AlgMetadataQuery mq ) { - double dRows = mq.getTupleCount( this ); - double dCpu = mq.getTupleCount( getInput() ) * program.getExprCount(); + double dRows = mq.getTupleCount( this ).orElse( Double.MAX_VALUE ); + double dCpu = mq.getTupleCount( getInput() ).orElse( Double.MAX_VALUE ) * program.getExprCount(); double dIo = 0; return planner.getCostFactory().makeCost( dRows, dCpu, dIo ); }