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); }
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); } }
public static RelDataType createTypeFromProjection( RelDataType type, List<String> columnNameList, RelDataTypeFactory typeFactory, boolean caseSensitive) { // If the names in columnNameList and type have case-sensitive differences, // the resulting type will use those from type. These are presumably more // canonical. final List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>(columnNameList.size()); for (String name : columnNameList) { RelDataTypeField field = type.getField(name, caseSensitive); fields.add(type.getFieldList().get(field.getIndex())); } return typeFactory.createStructType(fields); }
/** * Creates a record type with specified field names. * * <p>The array of field names may be null, or any of the names within it can be null. We * recommend using explicit names where possible, because it makes it much easier to figure out * the intent of fields when looking at planner output. * * @param typeFactory Type factory * @param exprs Expressions * @param names Field names, may be null, or elements may be null * @return Record type */ public static RelDataType createStructType( RelDataTypeFactory typeFactory, final RexNode[] exprs, final String[] names) { return typeFactory.createStructType( new RelDataTypeFactory.FieldInfo() { public int getFieldCount() { return exprs.length; } public String getFieldName(int index) { if (names == null) { return "$f" + index; } final String name = names[index]; if (name == null) { return "$f" + index; } return name; } public RelDataType getFieldType(int index) { return exprs[index].getType(); } }); }