Java Code Examples for org.apache.calcite.rel.RelNode#accept()

The following examples show how to use org.apache.calcite.rel.RelNode#accept() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: MycatCalcitePlanner.java    From Mycat2 with GNU General Public License v3.0 6 votes vote down vote up
public DatasourceInfo preComputeSeq(RelNode relNode) {
    MycatDBContext uponDBContext = dataContext.getUponDBContext();
    Map<String, List<SingeTargetSQLTable>> map = new HashMap<>();
    relNode.accept(new RelShuttleImpl() {
        @Override
        public RelNode visit(TableScan scan) {
            SingeTargetSQLTable unwrap = scan.getTable().unwrap(SingeTargetSQLTable.class);
            if (unwrap != null) {
                List<SingeTargetSQLTable> preComputationSQLTables = map.computeIfAbsent(uponDBContext.resolveFinalTargetName(unwrap.getTargetName()), s -> new ArrayList<>(1));
                preComputationSQLTables.add(unwrap);
            }
            return super.visit(scan);
        }
    });
    List<SingeTargetSQLTable> preSeq = new ArrayList<>();
    for (Map.Entry<String, List<SingeTargetSQLTable>> stringListEntry : map.entrySet()) {
        List<SingeTargetSQLTable> value = stringListEntry.getValue();
        int size = value.size() - 1;
        for (int i = 0; i < size; i++) {
            preSeq.add(value.get(i));
        }
    }
    return new DatasourceInfo(preSeq, map);
}
 
Example 2
Source File: RexSubQueryUtils.java    From dremio-oss with Apache License 2.0 6 votes vote down vote up
public boolean visit(final RelNode node) {
  if (node instanceof JdbcCrel) {
    return false;
  }

  for (RelNode input : node.getInputs()) {
    if (visit(input)) {
      return true;
    }
  }

  final RexSubQueryFinder subQueryFinder = new RexSubQueryFinder();
  node.accept(subQueryFinder);
  if (subQueryFinder.getFoundSubQuery()) {
    return true;
  }

  return false;
}
 
Example 3
Source File: SqlHintsConverterTest.java    From calcite with Apache License 2.0 6 votes vote down vote up
private void assertHintsEquals(
    String sql,
    String hint) {
  tester.getDiffRepos().assertEquals("sql", "${sql}", sql);
  String sql2 = tester.getDiffRepos().expand("sql", sql);
  final RelNode rel = tester.convertSqlToRel(sql2).project();

  assertNotNull(rel);
  assertValid(rel);

  final HintCollector collector = new HintCollector(hintsCollect);
  rel.accept(collector);
  StringBuilder builder = new StringBuilder(NL);
  for (String hintLine : hintsCollect) {
    builder.append(hintLine).append(NL);
  }
  tester.getDiffRepos().assertEquals("hints", hint, builder.toString());
}
 
Example 4
Source File: ViewTable.java    From Bats with Apache License 2.0 6 votes vote down vote up
private RelRoot expandView(RelOptTable.ToRelContext context,
    RelDataType rowType, String queryString) {
  try {
    final RelRoot root =
        context.expandView(rowType, queryString, schemaPath, viewPath);
    final RelNode rel = RelOptUtil.createCastRel(root.rel, rowType, true);
    // Expand any views
    final RelNode rel2 = rel.accept(
        new RelShuttleImpl() {
          @Override public RelNode visit(TableScan scan) {
            final RelOptTable table = scan.getTable();
            final TranslatableTable translatableTable =
                table.unwrap(TranslatableTable.class);
            if (translatableTable != null) {
              return translatableTable.toRel(context, table);
            }
            return super.visit(scan);
          }
        });
    return root.withRel(rel2);
  } catch (Exception e) {
    throw new RuntimeException("Error while parsing view definition: "
        + queryString, e);
  }
}
 
Example 5
Source File: SubQueryDecorrelator.java    From flink with Apache License 2.0 5 votes vote down vote up
/**
 * check whether a node has some input which have correlation condition.
 * e.g. SELECT * FROM l WHERE EXISTS (SELECT * FROM r LEFT JOIN (SELECT * FROM t WHERE t.j=l.b) t1 ON r.f=t1.k)
 * the above sql can not be converted to semi-join plan,
 * because the right input of Left-Join has the correlation condition(t.j=l.b).
 */
private void checkCorConditionOfInput(final RelNode input) {
	final RelShuttleImpl shuttle = new RelShuttleImpl() {
		final RexVisitor<Void> visitor = new RexVisitorImpl<Void>(true) {
			@Override
			public Void visitCorrelVariable(RexCorrelVariable correlVariable) {
				hasUnsupportedCorCondition = true;
				return super.visitCorrelVariable(correlVariable);
			}
		};

		@Override
		public RelNode visit(LogicalFilter filter) {
			filter.getCondition().accept(visitor);
			return super.visit(filter);
		}

		@Override
		public RelNode visit(LogicalProject project) {
			for (RexNode rex : project.getProjects()) {
				rex.accept(visitor);
			}
			return super.visit(project);
		}

		@Override
		public RelNode visit(LogicalJoin join) {
			join.getCondition().accept(visitor);
			return super.visit(join);
		}
	};
	input.accept(shuttle);
}
 
Example 6
Source File: PrelTransformer.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
private static RelNode convertToRelRoot(SqlHandlerConfig config, SqlNode node, RelTransformer relTransformer) throws RelConversionException {
  final boolean leafLimitEnabled = config.getContext().getPlannerSettings().isLeafLimitsEnabled();

  // First try and convert without "expanding" exists/in/subqueries
  final RelNode convertible = toConvertibleRelRoot(config, node, false, relTransformer);

  // Check for RexSubQuery in the converted rel tree, and make sure that the table scans underlying
  // rel node with RexSubQuery have the same JDBC convention.
  final RelNode convertedNodeNotExpanded = convertible;
  RexSubQueryUtils.RexSubQueryPushdownChecker checker = new RexSubQueryUtils.RexSubQueryPushdownChecker(null);
  checker.visit(convertedNodeNotExpanded);

  final RelNode convertedNodeWithoutRexSubquery;
  if (!checker.foundRexSubQuery()) {
    convertedNodeWithoutRexSubquery = convertedNodeNotExpanded;
  } else {
    convertedNodeWithoutRexSubquery = toConvertibleRelRoot(config, node, true, relTransformer);
  }

  // Convert with "expanding" exists/in subqueries (if applicable)
  // if we are having a RexSubQuery, this expanded tree will
  // have LogicalCorrelate rel nodes.
  final DremioVolcanoPlanner volcanoPlanner = (DremioVolcanoPlanner) convertedNodeWithoutRexSubquery.getCluster().getPlanner();
  final RelNode originalRoot = convertedNodeWithoutRexSubquery.accept(new InjectSample(leafLimitEnabled));
  volcanoPlanner.setOriginalRoot(originalRoot);
  return ExpansionNode.removeFromTree(convertedNodeWithoutRexSubquery.accept(new InjectSample(leafLimitEnabled)));
}
 
Example 7
Source File: RelFieldTrimmer.java    From calcite with Apache License 2.0 5 votes vote down vote up
protected TrimResult result(RelNode r, final Mapping mapping) {
  final RexBuilder rexBuilder = relBuilder.getRexBuilder();
  for (final CorrelationId correlation : r.getVariablesSet()) {
    r = r.accept(
        new CorrelationReferenceFinder() {
          protected RexNode handle(RexFieldAccess fieldAccess) {
            final RexCorrelVariable v =
                (RexCorrelVariable) fieldAccess.getReferenceExpr();
            if (v.id.equals(correlation)
                && v.getType().getFieldCount() == mapping.getSourceCount()) {
              final int old = fieldAccess.getField().getIndex();
              final int new_ = mapping.getTarget(old);
              final RelDataTypeFactory.Builder typeBuilder =
                  relBuilder.getTypeFactory().builder();
              for (int target : Util.range(mapping.getTargetCount())) {
                typeBuilder.add(
                    v.getType().getFieldList().get(mapping.getSource(target)));
              }
              final RexNode newV =
                  rexBuilder.makeCorrel(typeBuilder.build(), v.id);
              if (old != new_) {
                return rexBuilder.makeFieldAccess(newV, new_);
              }
            }
            return fieldAccess;
          }
        });
  }
  return new TrimResult(r, mapping);
}
 
Example 8
Source File: RelWriterTest.java    From calcite with Apache License 2.0 5 votes vote down vote up
/** Returns the schema of a {@link org.apache.calcite.rel.core.TableScan}
 * in this plan, or null if there are no scans. */
private RelOptSchema getSchema(RelNode rel) {
  final Holder<RelOptSchema> schemaHolder = Holder.of(null);
  rel.accept(
      new RelShuttleImpl() {
        @Override public RelNode visit(TableScan scan) {
          schemaHolder.set(scan.getTable().getRelOptSchema());
          return super.visit(scan);
        }
      });
  return schemaHolder.get();
}
 
Example 9
Source File: RelOptUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/** Finds which columns of a correlation variable are used within a
 * relational expression. */
public static ImmutableBitSet correlationColumns(CorrelationId id, RelNode rel) {
    final CorrelationCollector collector = new CorrelationCollector();
    rel.accept(collector);
    final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
    for (int field : collector.vuv.variableFields.get(id)) {
        if (field >= 0) {
            builder.set(field);
        }
    }
    return builder.build();
}
 
Example 10
Source File: RelOptUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Visits a particular child of a parent.
 */
protected RelNode visitChild(RelNode parent, int i, RelNode child) {
  inheritPaths.forEach(inheritPath -> inheritPath.right.push(i));
  try {
    RelNode child2 = child.accept(this);
    if (child2 != child) {
      final List<RelNode> newInputs = new ArrayList<>(parent.getInputs());
      newInputs.set(i, child2);
      return parent.copy(parent.getTraitSet(), newInputs);
    }
    return parent;
  } finally {
    inheritPaths.forEach(inheritPath -> inheritPath.right.pop());
  }
}
 
Example 11
Source File: RexShuttleTest.java    From calcite with Apache License 2.0 5 votes vote down vote up
/** Test case for
 * <a href="https://issues.apache.org/jira/browse/CALCITE-3165">[CALCITE-3165]
 * Project#accept(RexShuttle shuttle) does not update rowType</a>. */
@Test void testProjectUpdatesRowType() {
  final RelBuilder builder = RelBuilder.create(RelBuilderTest.config().build());

  // Equivalent SQL: SELECT deptno, sal FROM emp
  final RelNode root =
      builder
          .scan("EMP")
          .project(
              builder.field("DEPTNO"),
              builder.field("SAL"))
          .build();

  // Equivalent SQL: SELECT CAST(deptno AS VARCHAR), CAST(sal AS VARCHAR) FROM emp
  final RelNode rootWithCast =
      builder
          .scan("EMP")
          .project(
              builder.cast(builder.field("DEPTNO"), SqlTypeName.VARCHAR),
              builder.cast(builder.field("SAL"), SqlTypeName.VARCHAR))
          .build();
  final RelDataType type = rootWithCast.getRowType();

  // Transform the first expression into the second one, by using a RexShuttle
  // that converts every RexInputRef into a 'CAST(RexInputRef AS VARCHAR)'
  final RelNode rootWithCastViaRexShuttle = root.accept(new RexShuttle() {
    @Override public RexNode visitInputRef(RexInputRef inputRef) {
      return  builder.cast(inputRef, SqlTypeName.VARCHAR);
    }
  });
  final RelDataType type2 = rootWithCastViaRexShuttle.getRowType();

  assertThat(type, is(type2));
}
 
Example 12
Source File: SubstitutionUtils.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
/**
 * @return true if query plan matches the candidate plan, after removing the {@link ReplacementPointer} from the candidate plan
 */
public static boolean arePlansEqualIgnoringReplacementPointer(RelNode query, RelNode candidate) {
  Preconditions.checkNotNull(query, "query plan required");
  Preconditions.checkNotNull(candidate, "candidate plan required");

  final int queryCode = hash(query);
  final RelNode updatedCandidate = candidate.accept(REMOVE_REPLACEMENT_POINTER);
  final int candidateCode = hash(updatedCandidate);

  return queryCode == candidateCode;
}
 
Example 13
Source File: RelFieldTrimmer.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Trims the fields of an input relational expression.
 *
 * @param rel        Relational expression
 * @param input      Input relational expression, whose fields to trim
 * @param fieldsUsed Bitmap of fields needed by the consumer
 * @return New relational expression and its field mapping
 */
protected TrimResult trimChild(RelNode rel, RelNode input, final ImmutableBitSet fieldsUsed,
        Set<RelDataTypeField> extraFields) {
    final ImmutableBitSet.Builder fieldsUsedBuilder = fieldsUsed.rebuild();

    // Fields that define the collation cannot be discarded.
    final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
    final ImmutableList<RelCollation> collations = mq.collations(input);
    for (RelCollation collation : collations) {
        for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
            fieldsUsedBuilder.set(fieldCollation.getFieldIndex());
        }
    }

    // Correlating variables are a means for other relational expressions to use
    // fields.
    for (final CorrelationId correlation : rel.getVariablesSet()) {
        rel.accept(new CorrelationReferenceFinder() {
            @Override
            protected RexNode handle(RexFieldAccess fieldAccess) {
                final RexCorrelVariable v = (RexCorrelVariable) fieldAccess.getReferenceExpr();
                if (v.getCorrelationId().equals(correlation)) {
                    fieldsUsedBuilder.set(fieldAccess.getField().getIndex());
                }
                return fieldAccess;
            }
        });
    }

    return dispatchTrimFields(input, fieldsUsedBuilder.build(), extraFields);
}
 
Example 14
Source File: MoreRelOptUtil.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
protected RelNode visitChild(RelNode parent, int i, RelNode child) {
  if(!predicate.test(parent)){
    return child.accept(this);
  }

  return super.visitChild(parent, i, child);
}
 
Example 15
Source File: JoinRelBase.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
  // normalize join first
  RelNode normalized = JoinNormalizationRule.INSTANCE.normalize(this);
  if (normalized != this) {
    // If normalized, return sum of all converted/generated rels
    final Pointer<RelOptCost> cost = new Pointer<>(planner.getCostFactory().makeZeroCost());
    normalized.accept(new RelShuttleImpl() {
      @Override
      public RelNode visit(RelNode other) {
        cost.value = cost.value.plus(mq.getNonCumulativeCost(other));
        if (!(other instanceof Join)) {
          return super.visit(other);
        }
        return other;
      }
    });
    return cost.value;
  }

  // Compute filter cost
  RelOptCost remainingFilterCost;
  if (remaining.isAlwaysTrue()) {
    remainingFilterCost = planner.getCostFactory().makeZeroCost();
  } else {
    // Similar to FilterRelBase
    double inputRows = Math.max(mq.getRowCount(getLeft()), mq.getRowCount(getRight()));
    double compNum = inputRows;
    double rowCompNum = this.getRowType().getFieldCount() * inputRows ;

    final List<RexNode> conjunctions = RelOptUtil.conjunctions(condition);
    final int conjunctionsSize = conjunctions.size();
    for (int i = 0; i< conjunctionsSize; i++) {
      RexNode conjFilter = RexUtil.composeConjunction(this.getCluster().getRexBuilder(), conjunctions.subList(0, i + 1), false);
      compNum += RelMdUtil.estimateFilteredRows(this, conjFilter, mq);
    }

    double cpuCost = compNum * DremioCost.COMPARE_CPU_COST + rowCompNum * DremioCost.COPY_COST;
    Factory costFactory = (Factory)planner.getCostFactory();
    // Do not include input rows into the extra filter cost
    remainingFilterCost = costFactory.makeCost(0, cpuCost, 0, 0);
  }
  return remainingFilterCost.plus(doComputeSelfCost(planner, mq));
}
 
Example 16
Source File: DefaultSqlHandler.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override
protected RelNode visitChild(RelNode parent, int i, RelNode child) {
  child.accept(this);
  parent.getCluster().setMetadataProvider(metadataProvider);
  return parent;
}
 
Example 17
Source File: CalciteRunners.java    From Mycat2 with GNU General Public License v3.0 4 votes vote down vote up
@SneakyThrows
    public static RowBaseIterator run(String sql, MycatCalciteDataContext calciteDataContext, RelNode relNode) {
        SqlRecorder recorder = SqlRecorderRuntime.INSTANCE.getCurrentRecorder();
        Map<String, List<SingeTargetSQLTable>> map = new HashMap<>();
        relNode.accept(new RelShuttleImpl() {
            @Override
            public RelNode visit(TableScan scan) {
                SingeTargetSQLTable unwrap = scan.getTable().unwrap(SingeTargetSQLTable.class);
                if (unwrap != null && !unwrap.existsEnumerable()) {
                    List<SingeTargetSQLTable> tables = map.computeIfAbsent(unwrap.getTargetName(), s -> new ArrayList<>(2));
                    tables.add(unwrap);
                }
                return super.visit(scan);
            }
        });

        HepProgramBuilder hepProgramBuilder = new HepProgramBuilder();
        hepProgramBuilder.addMatchLimit(64);

        hepProgramBuilder.addRuleInstance(StreamUnionRule.INSTANCE);
        final HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build());
        planner2.setRoot(relNode);
        relNode = planner2.findBestExp();

        //check
        relNode.accept(new RelShuttleImpl() {
            @Override
            public RelNode visit(LogicalUnion union) {
                if (union.getInputs().size() > 2) {
                    throw new AssertionError("union input more 2");
                }
                return super.visit(union);
            }
        });
        long startGetConnectionTime = TimeProvider.INSTANCE.now();
        fork(sql, calciteDataContext, map);
        long cbo = TimeProvider.INSTANCE.now();
        recorder.addRecord(SqlRecorderType.GET_CONNECTION, sql, cbo - startGetConnectionTime);
        ArrayBindable bindable1 = Interpreters.bindable(relNode);
        long execution_start = TimeProvider.INSTANCE.now();
        recorder.addRecord(SqlRecorderType.CBO, sql, execution_start - cbo);
//        EnumerableInterpretable.toBindable()
        Enumerable<Object[]> bind = bindable1.bind(calciteDataContext);
        Enumerator<Object[]> enumerator = bind.enumerator();

        return new EnumeratorRowIterator(CalciteConvertors.getMycatRowMetaData(relNode.getRowType()), enumerator,
                () -> {
                    recorder.addRecord(SqlRecorderType.EXECUTION_TIME, sql, TimeProvider.INSTANCE.now()-execution_start);
                    recorder.addRecord(SqlRecorderType.AT_END, sql, TimeProvider.INSTANCE.now());
                });
    }
 
Example 18
Source File: PrelTransformer.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
/**
 *  Given a relNode tree for SELECT statement, convert to Dremio Logical RelNode tree.
 * @param relNode
 * @return
 * @throws SqlUnsupportedException
 * @throws RelConversionException
 */
public static Rel convertToDrel(SqlHandlerConfig config, final RelNode relNode) throws SqlUnsupportedException, RelConversionException {

  try {
    final RelNode trimmed = trimFields(relNode, true, config.getContext().getPlannerSettings().isRelPlanningEnabled());
    final RelNode preLog = transform(config, PlannerType.HEP_AC, PlannerPhase.PRE_LOGICAL, trimmed, trimmed.getTraitSet(), true);

    final RelTraitSet logicalTraits = preLog.getTraitSet().plus(Rel.LOGICAL);
    final RelNode adjusted = transform(config, PlannerType.VOLCANO, PlannerPhase.LOGICAL, preLog, logicalTraits, true);

    final Catalog catalog = config.getContext().getCatalog();
    if (catalog instanceof CachingCatalog) {
      config.getObserver().tablesCollected(catalog.getAllRequestedTables());
    }

    final RelNode intermediateNode;
    if (config.getContext().getPlannerSettings().removeRowCountAdjustment()) {
      intermediateNode = adjusted.accept(new RelShuttleImpl() {
          @Override
          public RelNode visit(TableScan scan) {
            if (scan instanceof FilesystemScanDrel) {
              FilesystemScanDrel scanDrel = (FilesystemScanDrel) scan;
              return new FilesystemScanDrel(
                scanDrel.getCluster(),
                scanDrel.getTraitSet(),
                scanDrel.getTable(),
                scanDrel.getPluginId(),
                scanDrel.getTableMetadata(),
                scanDrel.getProjectedColumns(),
                1.0);
            }
            return super.visit(scan);
          }
        });
    } else {
      intermediateNode = adjusted;
    }

    RelNode postLogical;
    if (config.getContext().getPlannerSettings().isRelPlanningEnabled()) {
      final RelNode decorrelatedNode = DremioRelDecorrelator.decorrelateQuery(intermediateNode, DremioRelFactories.LOGICAL_BUILDER.create(intermediateNode.getCluster(), null), true, true);
      final RelNode jdbcPushDown = transform(config, PlannerType.HEP_AC, PlannerPhase.RELATIONAL_PLANNING, decorrelatedNode, decorrelatedNode.getTraitSet().plus(Rel.LOGICAL), true);
      postLogical = jdbcPushDown.accept(new ShortenJdbcColumnAliases()).accept(new ConvertJdbcLogicalToJdbcRel(DremioRelFactories.LOGICAL_BUILDER));
    } else {
      postLogical = intermediateNode;
    }

    // Do Join Planning.
    final RelNode preConvertedRelNode = transform(config, PlannerType.HEP_BOTTOM_UP, PlannerPhase.JOIN_PLANNING_MULTI_JOIN, postLogical, postLogical.getTraitSet(), true);
    final RelNode convertedRelNode = transform(config, PlannerType.HEP_BOTTOM_UP, PlannerPhase.JOIN_PLANNING_OPTIMIZATION, preConvertedRelNode, preConvertedRelNode.getTraitSet(), true);

    FlattenRelFinder flattenFinder = new FlattenRelFinder();
    final RelNode flattendPushed;
    if (flattenFinder.run(convertedRelNode)) {
      flattendPushed = transform(config, PlannerType.VOLCANO, PlannerPhase.FLATTEN_PUSHDOWN,
        convertedRelNode, convertedRelNode.getTraitSet(), true);
    } else {
      flattendPushed = convertedRelNode;
    }

    final Rel drel = (Rel) flattendPushed;

    if (drel instanceof TableModify) {
      throw new UnsupportedOperationException("TableModify " + drel);
    } else {
      final Optional<SubstitutionInfo> acceleration = findUsedMaterializations(config, drel);
      if (acceleration.isPresent()) {
        config.getObserver().planAccelerated(acceleration.get());
      }
      return drel;
    }
  } catch (RelOptPlanner.CannotPlanException ex) {
    logger.error(ex.getMessage(), ex);

    if(JoinUtils.checkCartesianJoin(relNode, Lists.<Integer>newArrayList(), Lists.<Integer>newArrayList(), Lists.<Boolean>newArrayList())) {
      throw new UnsupportedRelOperatorException("This query cannot be planned\u2014possibly due to use of an unsupported feature.");
    } else {
      throw ex;
    }
  }
}
 
Example 19
Source File: PrelTransformer.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
private static RelNode convertToRelRootAndJdbc(SqlHandlerConfig config, SqlNode node, RelTransformer relTransformer) throws RelConversionException {

    // First try and convert without "expanding" exists/in/subqueries
    final RelNode convertible = toConvertibleRelRoot(config, node, false, relTransformer);

    // Check for RexSubQuery in the converted rel tree, and make sure that the table scans underlying
    // rel node with RexSubQuery have the same JDBC convention.
    final RelNode convertedNodeNotExpanded = convertible;
    RexSubQueryUtils.RexSubQueryPushdownChecker checker = new RexSubQueryUtils.RexSubQueryPushdownChecker(null);
    checker.visit(convertedNodeNotExpanded);

    final RelNode convertedNodeWithoutRexSubquery;
    final RelNode convertedNode;
    if (!checker.foundRexSubQuery()) {
      // If the not-expanded rel tree doesn't have any rex sub query, then everything is good.
      convertedNode = convertedNodeNotExpanded;
      convertedNodeWithoutRexSubquery = convertedNodeNotExpanded;
    } else {
      // If there is a rexSubQuery, then get the ones without (don't pass in SqlHandlerConfig here since we don't want to record it twice)
      convertedNodeWithoutRexSubquery = toConvertibleRelRoot(config, node, true, relTransformer);
      if (!checker.canPushdownRexSubQuery()) {
        // if there are RexSubQuery nodes with none-jdbc convention, abandon and expand the entire tree
        convertedNode = convertedNodeWithoutRexSubquery;
      } else {
        convertedNode = convertedNodeNotExpanded;
      }
    }

    final boolean leafLimitEnabled = config.getContext().getPlannerSettings().isLeafLimitsEnabled();

    { // Set original root in volcano planner for acceleration (in this case, do not inject JdbcCrel or JdbcRel)
      final DremioVolcanoPlanner volcanoPlanner = (DremioVolcanoPlanner) convertedNodeNotExpanded.getCluster().getPlanner();

      final RelNode originalRoot = convertedNodeWithoutRexSubquery.accept(new InjectSample(leafLimitEnabled));
      volcanoPlanner.setOriginalRoot(originalRoot);
    }

    // Now, transform jdbc nodes to Convention.NONE.  To do so, we need to inject a jdbc logical on top
    // of JDBC table scans with high cost and then plan to reduce the cost.
    final Stopwatch stopwatch = Stopwatch.createStarted();
    final RelNode injectJdbcLogical = ExpansionNode.removeFromTree(convertedNode.accept(new InjectSample(leafLimitEnabled)));

    final RelNode jdbcPushedPartial = transform(config, PlannerType.HEP_AC, PlannerPhase.JDBC_PUSHDOWN, injectJdbcLogical, injectJdbcLogical.getTraitSet(), false);

    // Transform all the subquery reltree into jdbc as well! If any of them fail, we abort and just use the expanded reltree.
    final RelsWithRexSubQueryTransformer transformer = new RelsWithRexSubQueryTransformer(config);
    final RelNode jdbcPushed = jdbcPushedPartial.accept(transformer);

    // Check that we do not have non-jdbc subqueries, if we do, then we have to abort and do a complete conversion.
    final FindNonJdbcConventionRexSubQuery noRexSubQueryChecker = new FindNonJdbcConventionRexSubQuery();
    final boolean found = transformer.failed() ? false : noRexSubQueryChecker.visit(jdbcPushed);

    final RelNode finalConvertedNode;
    if (transformer.failed() || found) {
      log("Failed to pushdown RexSubquery. Applying JDBC pushdown to query with IN/EXISTS/SCALAR sub-queries converted to joins.", jdbcPushed, logger, null);
      final RelNode expandedWithSample = convertedNodeWithoutRexSubquery.accept(new InjectSample(leafLimitEnabled));
      finalConvertedNode = transform(config,PlannerType.HEP_AC, PlannerPhase.JDBC_PUSHDOWN, expandedWithSample,
        expandedWithSample.getTraitSet(), false).accept(new ConvertJdbcLogicalToJdbcRel(DremioRelFactories.CALCITE_LOGICAL_BUILDER));
    } else {
      finalConvertedNode = jdbcPushed.accept(new ShortenJdbcColumnAliases()).accept(new ConvertJdbcLogicalToJdbcRel(DremioRelFactories.CALCITE_LOGICAL_BUILDER));
    }
    config.getObserver().planRelTransform(PlannerPhase.JDBC_PUSHDOWN, null, convertedNode, finalConvertedNode, stopwatch.elapsed(TimeUnit.MILLISECONDS));



    return finalConvertedNode;
  }
 
Example 20
Source File: FindHardDistributionScans.java    From Bats with Apache License 2.0 3 votes vote down vote up
/**
 * Can the given <code>relTree</code> be executed in single fragment mode? For now this returns false when the
 * <code>relTree</code> contains one or more scans with hard affinity requirements.
 *
 * @param relTree
 * @return
 */
public static boolean canForceSingleMode(final RelNode relTree) {
  final FindHardDistributionScans hdVisitor = new FindHardDistributionScans();
  relTree.accept(hdVisitor);
  // Can't run in single fragment mode if the query contains a table which has hard distribution requirement.
  return !hdVisitor.contains();
}