public Boolean areColumnsUnique(ProjectRelBase rel, BitSet columns, boolean ignoreNulls) {
    // ProjectRel maps a set of rows to a different set;
    // Without knowledge of the mapping function(whether it
    // preserves uniqueness), it is only safe to derive uniqueness
    // info from the child of a project when the mapping is f(a) => a.
    //
    // Also need to map the input column set to the corresponding child
    // references

    List<RexNode> projExprs = rel.getProjects();
    BitSet childColumns = new BitSet();
    for (int bit : BitSets.toIter(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;
        }
        RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
        RelDataType castType = typeFactory.createTypeWithNullability(projExpr.getType(), true);
        RelDataType origType = typeFactory.createTypeWithNullability(castOperand.getType(), true);
        if (castType.equals(origType)) {
          childColumns.set(((RexInputRef) castOperand).getIndex());
        }
      } else {
        // If the expression will not influence uniqueness of the
        // projection, then skip it.
        continue;
      }
    }

    // If no columns can affect uniqueness, then return unknown
    if (childColumns.cardinality() == 0) {
      return null;
    }

    return RelMetadataQuery.areColumnsUnique(rel.getChild(), childColumns, ignoreNulls);
  }
Пример #2
0
 /**
  * Generates a cast for a row type.
  *
  * @param rexBuilder RexBuilder to use for constructing casts
  * @param lhsRowType target row type
  * @param rhsExps expressions to be cast
  * @return cast expressions
  */
 public static RexNode[] generateCastExpressions(
     RexBuilder rexBuilder, RelDataType lhsRowType, RexNode[] rhsExps) {
   RelDataTypeField[] lhsFields = lhsRowType.getFields();
   final int fieldCount = lhsFields.length;
   RexNode[] castExps = new RexNode[fieldCount];
   assert fieldCount == rhsExps.length;
   for (int i = 0; i < fieldCount; ++i) {
     RelDataTypeField lhsField = lhsFields[i];
     RelDataType lhsType = lhsField.getType();
     RelDataType rhsType = rhsExps[i].getType();
     if (lhsType.equals(rhsType)) {
       castExps[i] = rhsExps[i];
     } else {
       castExps[i] = rexBuilder.makeCast(lhsType, rhsExps[i]);
     }
   }
   return castExps;
 }
    private void reduceCasts(RexCall outerCast) {
      RexNode[] operands = outerCast.getOperands();
      if (operands.length != 1) {
        return;
      }
      RelDataType outerCastType = outerCast.getType();
      RelDataType operandType = operands[0].getType();
      if (operandType.equals(outerCastType)) {
        removableCasts.add(outerCast);
        return;
      }

      // See if the reduction
      // CAST((CAST x AS type) AS type NOT NULL)
      // -> CAST(x AS type NOT NULL)
      // applies.  TODO jvs 15-Dec-2008:  consider
      // similar cases for precision changes.
      if (!(operands[0] instanceof RexCall)) {
        return;
      }
      RexCall innerCast = (RexCall) operands[0];
      if (innerCast.getOperator() != SqlStdOperatorTable.castFunc) {
        return;
      }
      if (innerCast.getOperands().length != 1) {
        return;
      }
      RelDataTypeFactory typeFactory = preparingStmt.getFarragoTypeFactory();
      RelDataType outerTypeNullable = typeFactory.createTypeWithNullability(outerCastType, true);
      RelDataType innerTypeNullable = typeFactory.createTypeWithNullability(operandType, true);
      if (outerTypeNullable != innerTypeNullable) {
        return;
      }
      if (operandType.isNullable()) {
        removableCasts.add(innerCast);
      }
    }