use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.
the class RelMdColumnUniqueness method areProjectColumnsUnique.
@Nullable
private static Boolean areProjectColumnsUnique(SingleRel rel, RelMetadataQuery mq, ImmutableBitSet columns, boolean ignoreNulls, List<RexNode> projExprs) {
RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
ImmutableBitSet.Builder childColumns = ImmutableBitSet.builder();
for (int bit : columns) {
RexNode projExpr = projExprs.get(bit);
if (projExpr instanceof RexInputRef) {
childColumns.set(((RexInputRef) projExpr).getIndex());
} else if (projExpr instanceof RexCall && ignoreNulls) {
// If the expression is a cast such that the types are the same
// except for the nullability, then if we're ignoring nulls,
// it doesn't matter whether the underlying column reference
// is nullable. Check that the types are the same by making a
// nullable copy of both types and then comparing them.
RexCall call = (RexCall) projExpr;
if (call.getOperator() != SqlStdOperatorTable.CAST) {
continue;
}
RexNode castOperand = call.getOperands().get(0);
if (!(castOperand instanceof RexInputRef)) {
continue;
}
RelDataType castType = typeFactory.createTypeWithNullability(projExpr.getType(), true);
RelDataType origType = typeFactory.createTypeWithNullability(castOperand.getType(), true);
if (castType.equals(origType)) {
childColumns.set(((RexInputRef) castOperand).getIndex());
}
} else {
// projection, then skip it.
continue;
}
}
// If no columns can affect uniqueness, then return unknown
if (childColumns.cardinality() == 0) {
return null;
}
return mq.areColumnsUnique(rel.getInput(), childColumns.build(), ignoreNulls);
}
use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.
the class RelMdExpressionLineage method getExpressionLineage.
/**
* Expression lineage from {@link Join}.
*
* <p>We only extract the lineage for INNER joins.
*/
@Nullable
public Set<RexNode> getExpressionLineage(Join rel, RelMetadataQuery mq, RexNode outputExpression) {
final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
final RelNode leftInput = rel.getLeft();
final RelNode rightInput = rel.getRight();
final int nLeftColumns = leftInput.getRowType().getFieldList().size();
// Extract input fields referenced by expression
final ImmutableBitSet inputFieldsUsed = extractInputRefs(outputExpression);
if (rel.getJoinType().isOuterJoin()) {
// If we reference the inner side, we will bail out
if (rel.getJoinType() == JoinRelType.LEFT) {
ImmutableBitSet rightFields = ImmutableBitSet.range(nLeftColumns, rel.getRowType().getFieldCount());
if (inputFieldsUsed.intersects(rightFields)) {
// We cannot map origin of this expression.
return null;
}
} else if (rel.getJoinType() == JoinRelType.RIGHT) {
ImmutableBitSet leftFields = ImmutableBitSet.range(0, nLeftColumns);
if (inputFieldsUsed.intersects(leftFields)) {
// We cannot map origin of this expression.
return null;
}
} else {
// We cannot map origin of this expression.
return null;
}
}
// Gather table references
final Set<RelTableRef> leftTableRefs = mq.getTableReferences(leftInput);
if (leftTableRefs == null) {
// Bail out
return null;
}
final Set<RelTableRef> rightTableRefs = mq.getTableReferences(rightInput);
if (rightTableRefs == null) {
// Bail out
return null;
}
final Multimap<List<String>, RelTableRef> qualifiedNamesToRefs = HashMultimap.create();
final Map<RelTableRef, RelTableRef> currentTablesMapping = new HashMap<>();
for (RelTableRef leftRef : leftTableRefs) {
qualifiedNamesToRefs.put(leftRef.getQualifiedName(), leftRef);
}
for (RelTableRef rightRef : rightTableRefs) {
int shift = 0;
Collection<RelTableRef> lRefs = qualifiedNamesToRefs.get(rightRef.getQualifiedName());
if (lRefs != null) {
shift = lRefs.size();
}
currentTablesMapping.put(rightRef, RelTableRef.of(rightRef.getTable(), shift + rightRef.getEntityNumber()));
}
// Infer column origin expressions for given references
final Map<RexInputRef, Set<RexNode>> mapping = new LinkedHashMap<>();
for (int idx : inputFieldsUsed) {
if (idx < nLeftColumns) {
final RexInputRef inputRef = RexInputRef.of(idx, leftInput.getRowType().getFieldList());
final Set<RexNode> originalExprs = mq.getExpressionLineage(leftInput, inputRef);
if (originalExprs == null) {
// Bail out
return null;
}
// Left input references remain unchanged
mapping.put(RexInputRef.of(idx, rel.getRowType().getFieldList()), originalExprs);
} else {
// Right input.
final RexInputRef inputRef = RexInputRef.of(idx - nLeftColumns, rightInput.getRowType().getFieldList());
final Set<RexNode> originalExprs = mq.getExpressionLineage(rightInput, inputRef);
if (originalExprs == null) {
// Bail out
return null;
}
// Right input references might need to be updated if there are
// table names clashes with left input
final RelDataType fullRowType = SqlValidatorUtil.createJoinType(rexBuilder.getTypeFactory(), rel.getLeft().getRowType(), rel.getRight().getRowType(), null, ImmutableList.of());
final Set<RexNode> updatedExprs = ImmutableSet.copyOf(Util.transform(originalExprs, e -> RexUtil.swapTableReferences(rexBuilder, e, currentTablesMapping)));
mapping.put(RexInputRef.of(idx, fullRowType), updatedExprs);
}
}
// Return result
return createAllPossibleExpressions(rexBuilder, outputExpression, mapping);
}
use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.
the class RelMdExpressionLineage method getExpressionLineage.
/**
* Expression lineage from Calc.
*/
@Nullable
public Set<RexNode> getExpressionLineage(Calc calc, RelMetadataQuery mq, RexNode outputExpression) {
final RelNode input = calc.getInput();
final RexBuilder rexBuilder = calc.getCluster().getRexBuilder();
// Extract input fields referenced by expression
final ImmutableBitSet inputFieldsUsed = extractInputRefs(outputExpression);
// Infer column origin expressions for given references
final Map<RexInputRef, Set<RexNode>> mapping = new LinkedHashMap<>();
Pair<ImmutableList<RexNode>, ImmutableList<RexNode>> calcProjectsAndFilter = calc.getProgram().split();
for (int idx : inputFieldsUsed) {
final RexNode inputExpr = calcProjectsAndFilter.getKey().get(idx);
final Set<RexNode> originalExprs = mq.getExpressionLineage(input, inputExpr);
if (originalExprs == null) {
// Bail out
return null;
}
final RexInputRef ref = RexInputRef.of(idx, calc.getRowType().getFieldList());
mapping.put(ref, originalExprs);
}
// Return result
return createAllPossibleExpressions(rexBuilder, outputExpression, mapping);
}
use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.
the class RelMdExpressionLineage method getExpressionLineage.
/**
* Expression lineage from {@link Union}.
*
* <p>For Union operator, we might be able to extract multiple origins for the
* references in the given expression.
*/
@Nullable
public Set<RexNode> getExpressionLineage(Union rel, RelMetadataQuery mq, RexNode outputExpression) {
final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
// Extract input fields referenced by expression
final ImmutableBitSet inputFieldsUsed = extractInputRefs(outputExpression);
// Infer column origin expressions for given references
final Multimap<List<String>, RelTableRef> qualifiedNamesToRefs = HashMultimap.create();
final Map<RexInputRef, Set<RexNode>> mapping = new LinkedHashMap<>();
for (RelNode input : rel.getInputs()) {
// Gather table references
final Map<RelTableRef, RelTableRef> currentTablesMapping = new HashMap<>();
final Set<RelTableRef> tableRefs = mq.getTableReferences(input);
if (tableRefs == null) {
// Bail out
return null;
}
for (RelTableRef tableRef : tableRefs) {
int shift = 0;
Collection<RelTableRef> lRefs = qualifiedNamesToRefs.get(tableRef.getQualifiedName());
if (lRefs != null) {
shift = lRefs.size();
}
currentTablesMapping.put(tableRef, RelTableRef.of(tableRef.getTable(), shift + tableRef.getEntityNumber()));
}
// Map references
for (int idx : inputFieldsUsed) {
final RexInputRef inputRef = RexInputRef.of(idx, input.getRowType().getFieldList());
final Set<RexNode> originalExprs = mq.getExpressionLineage(input, inputRef);
if (originalExprs == null) {
// Bail out
return null;
}
// References might need to be updated
final RexInputRef ref = RexInputRef.of(idx, rel.getRowType().getFieldList());
final Set<RexNode> updatedExprs = originalExprs.stream().map(e -> RexUtil.swapTableReferences(rexBuilder, e, currentTablesMapping)).collect(Collectors.toSet());
final Set<RexNode> set = mapping.get(ref);
if (set != null) {
set.addAll(updatedExprs);
} else {
mapping.put(ref, updatedExprs);
}
}
// Add to existing qualified names
for (RelTableRef newRef : currentTablesMapping.values()) {
qualifiedNamesToRefs.put(newRef.getQualifiedName(), newRef);
}
}
// Return result
return createAllPossibleExpressions(rexBuilder, outputExpression, mapping);
}
use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.
the class RelMdAllPredicates method getAllPredicates.
/**
* Add the Join condition to the list obtained from the input.
*/
@Nullable
public RelOptPredicateList getAllPredicates(Join join, RelMetadataQuery mq) {
if (join.getJoinType().isOuterJoin()) {
// We cannot map origin of this expression.
return null;
}
final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
final RexNode pred = join.getCondition();
final Multimap<List<String>, RelTableRef> qualifiedNamesToRefs = HashMultimap.create();
RelOptPredicateList newPreds = RelOptPredicateList.EMPTY;
for (RelNode input : join.getInputs()) {
final RelOptPredicateList inputPreds = mq.getAllPredicates(input);
if (inputPreds == null) {
// Bail out
return null;
}
// Gather table references
final Set<RelTableRef> tableRefs = mq.getTableReferences(input);
if (tableRefs == null) {
return null;
}
if (input == join.getLeft()) {
// Left input references remain unchanged
for (RelTableRef leftRef : tableRefs) {
qualifiedNamesToRefs.put(leftRef.getQualifiedName(), leftRef);
}
newPreds = newPreds.union(rexBuilder, inputPreds);
} else {
// Right input references might need to be updated if there are table name
// clashes with left input
final Map<RelTableRef, RelTableRef> currentTablesMapping = new HashMap<>();
for (RelTableRef rightRef : tableRefs) {
int shift = 0;
Collection<RelTableRef> lRefs = qualifiedNamesToRefs.get(rightRef.getQualifiedName());
if (lRefs != null) {
shift = lRefs.size();
}
currentTablesMapping.put(rightRef, RelTableRef.of(rightRef.getTable(), shift + rightRef.getEntityNumber()));
}
final List<RexNode> updatedPreds = Util.transform(inputPreds.pulledUpPredicates, e -> RexUtil.swapTableReferences(rexBuilder, e, currentTablesMapping));
newPreds = newPreds.union(rexBuilder, RelOptPredicateList.of(rexBuilder, updatedPreds));
}
}
// Extract input fields referenced by Join condition
final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<>();
final RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(inputExtraFields);
pred.accept(inputFinder);
final ImmutableBitSet inputFieldsUsed = inputFinder.build();
// Infer column origin expressions for given references
final Map<RexInputRef, Set<RexNode>> mapping = new LinkedHashMap<>();
final RelDataType fullRowType = SqlValidatorUtil.createJoinType(rexBuilder.getTypeFactory(), join.getLeft().getRowType(), join.getRight().getRowType(), null, ImmutableList.of());
for (int idx : inputFieldsUsed) {
final RexInputRef inputRef = RexInputRef.of(idx, fullRowType.getFieldList());
final Set<RexNode> originalExprs = mq.getExpressionLineage(join, inputRef);
if (originalExprs == null) {
// Bail out
return null;
}
final RexInputRef ref = RexInputRef.of(idx, fullRowType.getFieldList());
mapping.put(ref, originalExprs);
}
// Replace with new expressions and return union of predicates
final Set<RexNode> allExprs = RelMdExpressionLineage.createAllPossibleExpressions(rexBuilder, pred, mapping);
if (allExprs == null) {
return null;
}
return newPreds.union(rexBuilder, RelOptPredicateList.of(rexBuilder, allExprs));
}
Aggregations