use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class SqlTypeUtil method isComparable.
/**
* Returns whether two types are comparable. They need to be scalar types of
* the same family, or struct types whose fields are pairwise comparable.
*
* @param type1 First type
* @param type2 Second type
* @return Whether types are comparable
*/
public static boolean isComparable(RelDataType type1, RelDataType type2) {
if (type1.isStruct() != type2.isStruct()) {
return false;
}
if (type1.isStruct()) {
int n = type1.getFieldCount();
if (n != type2.getFieldCount()) {
return false;
}
for (Pair<RelDataTypeField, RelDataTypeField> pair : Pair.zip(type1.getFieldList(), type2.getFieldList())) {
if (!isComparable(pair.left.getType(), pair.right.getType())) {
return false;
}
}
return true;
}
RelDataTypeFamily family1 = null;
RelDataTypeFamily family2 = null;
// the Saffron type system happy.
if (type1.getSqlTypeName() != null) {
family1 = type1.getSqlTypeName().getFamily();
}
if (type2.getSqlTypeName() != null) {
family2 = type2.getSqlTypeName().getFamily();
}
if (family1 == null) {
family1 = type1.getFamily();
}
if (family2 == null) {
family2 = type2.getFamily();
}
if (family1 == family2) {
return true;
}
// If one of the arguments is of type 'ANY', return true.
if (family1 == SqlTypeFamily.ANY || family2 == SqlTypeFamily.ANY) {
return true;
}
// If one of the arguments is of type 'NULL', return true.
if (family1 == SqlTypeFamily.NULL || family2 == SqlTypeFamily.NULL) {
return true;
}
// We can implicitly convert from character to date
if (family1 == SqlTypeFamily.CHARACTER && canConvertStringInCompare(family2) || family2 == SqlTypeFamily.CHARACTER && canConvertStringInCompare(family1)) {
return true;
}
return false;
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class SqlTypeUtil method canCastFrom.
/**
* Compares two types and returns true if fromType can be cast to toType.
*
* <p>REVIEW jvs 17-Dec-2004: the coerce param below shouldn't really be
* necessary. We're using it as a hack because
* {@link SqlTypeFactoryImpl#leastRestrictiveSqlType} isn't complete enough
* yet. Once it is, this param (and the non-coerce rules of
* {@link SqlTypeAssignmentRules}) should go away.
*
* @param toType target of assignment
* @param fromType source of assignment
* @param coerce if true, the SQL rules for CAST are used; if false, the
* rules are similar to Java; e.g. you can't assign short x =
* (int) y, and you can't assign int x = (String) z.
* @return true iff cast is legal
*/
public static boolean canCastFrom(RelDataType toType, RelDataType fromType, boolean coerce) {
if (toType == fromType) {
return true;
}
if (isAny(toType) || isAny(fromType)) {
return true;
}
final SqlTypeName fromTypeName = fromType.getSqlTypeName();
final SqlTypeName toTypeName = toType.getSqlTypeName();
if (toType.isStruct() || fromType.isStruct()) {
if (toTypeName == SqlTypeName.DISTINCT) {
if (fromTypeName == SqlTypeName.DISTINCT) {
// can't cast between different distinct types
return false;
}
return canCastFrom(toType.getFieldList().get(0).getType(), fromType, coerce);
} else if (fromTypeName == SqlTypeName.DISTINCT) {
return canCastFrom(toType, fromType.getFieldList().get(0).getType(), coerce);
} else if (toTypeName == SqlTypeName.ROW) {
if (fromTypeName != SqlTypeName.ROW) {
return false;
}
int n = toType.getFieldCount();
if (fromType.getFieldCount() != n) {
return false;
}
for (int i = 0; i < n; ++i) {
RelDataTypeField toField = toType.getFieldList().get(i);
RelDataTypeField fromField = fromType.getFieldList().get(i);
if (!canCastFrom(toField.getType(), fromField.getType(), coerce)) {
return false;
}
}
return true;
} else if (toTypeName == SqlTypeName.MULTISET) {
if (!fromType.isStruct()) {
return false;
}
if (fromTypeName != SqlTypeName.MULTISET) {
return false;
}
return canCastFrom(toType.getComponentType(), fromType.getComponentType(), coerce);
} else if (fromTypeName == SqlTypeName.MULTISET) {
return false;
} else {
return toType.getFamily() == fromType.getFamily();
}
}
RelDataType c1 = toType.getComponentType();
if (c1 != null) {
RelDataType c2 = fromType.getComponentType();
if (c2 == null) {
return false;
}
return canCastFrom(c1, c2, coerce);
}
if ((isInterval(fromType) && isExactNumeric(toType)) || (isInterval(toType) && isExactNumeric(fromType))) {
IntervalSqlType intervalType = (IntervalSqlType) (isInterval(fromType) ? fromType : toType);
if (!intervalType.getIntervalQualifier().isSingleDatetimeField()) {
// intervals with a single datetime field.
return false;
}
}
if (toTypeName == null || fromTypeName == null) {
return false;
}
// REVIEW jvs 9-Feb-2009: we don't impose SQL rules for character sets
// here; instead, we do that in SqlCastFunction. The reason is that
// this method is called from at least one place (MedJdbcNameDirectory)
// where internally a cast across character repertoires is OK. Should
// probably clean that up.
SqlTypeAssignmentRules rules = SqlTypeAssignmentRules.instance(coerce);
return rules.canCastFrom(toTypeName, fromTypeName);
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class IdentifierNamespace method validateImpl.
public RelDataType validateImpl(RelDataType targetRowType) {
resolvedNamespace = Preconditions.checkNotNull(resolveImpl(id));
if (resolvedNamespace instanceof TableNamespace) {
SqlValidatorTable table = resolvedNamespace.getTable();
if (validator.shouldExpandIdentifiers()) {
// TODO: expand qualifiers for column references also
List<String> qualifiedNames = table.getQualifiedName();
if (qualifiedNames != null) {
// Assign positions to the components of the fully-qualified
// identifier, as best we can. We assume that qualification
// adds names to the front, e.g. FOO.BAR becomes BAZ.FOO.BAR.
List<SqlParserPos> poses = new ArrayList<>(Collections.nCopies(qualifiedNames.size(), id.getParserPosition()));
int offset = qualifiedNames.size() - id.names.size();
// reader.
if (offset >= 0) {
for (int i = 0; i < id.names.size(); i++) {
poses.set(i + offset, id.getComponentParserPosition(i));
}
}
id.setNames(qualifiedNames, poses);
}
}
}
RelDataType rowType = resolvedNamespace.getRowType();
if (extendList != null) {
if (!(resolvedNamespace instanceof TableNamespace)) {
throw new RuntimeException("cannot convert");
}
resolvedNamespace = ((TableNamespace) resolvedNamespace).extend(extendList);
rowType = resolvedNamespace.getRowType();
}
// Build a list of monotonic expressions.
final ImmutableList.Builder<Pair<SqlNode, SqlMonotonicity>> builder = ImmutableList.builder();
List<RelDataTypeField> fields = rowType.getFieldList();
for (RelDataTypeField field : fields) {
final String fieldName = field.getName();
final SqlMonotonicity monotonicity = resolvedNamespace.getMonotonicity(fieldName);
if (monotonicity != SqlMonotonicity.NOT_MONOTONIC) {
builder.add(Pair.of((SqlNode) new SqlIdentifier(fieldName, SqlParserPos.ZERO), monotonicity));
}
}
monotonicExprs = builder.build();
// Validation successful.
return rowType;
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class ListScope method resolveColumn.
public RelDataType resolveColumn(String columnName, SqlNode ctx) {
final SqlNameMatcher nameMatcher = validator.catalogReader.nameMatcher();
int found = 0;
RelDataType type = null;
for (ScopeChild child : children) {
SqlValidatorNamespace childNs = child.namespace;
final RelDataType childRowType = childNs.getRowType();
final RelDataTypeField field = nameMatcher.field(childRowType, columnName);
if (field != null) {
found++;
type = field.getType();
}
}
switch(found) {
case 0:
return null;
case 1:
return type;
default:
throw validator.newValidationError(ctx, RESOURCE.columnAmbiguous(columnName));
}
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class AliasNamespace method validateImpl.
// ~ Methods ----------------------------------------------------------------
protected RelDataType validateImpl(RelDataType targetRowType) {
final List<String> nameList = new ArrayList<String>();
final List<SqlNode> operands = call.getOperandList();
final SqlValidatorNamespace childNs = validator.getNamespace(operands.get(0));
final RelDataType rowType = childNs.getRowTypeSansSystemColumns();
final List<SqlNode> columnNames = Util.skip(operands, 2);
for (final SqlNode operand : columnNames) {
String name = ((SqlIdentifier) operand).getSimple();
if (nameList.contains(name)) {
throw validator.newValidationError(operand, RESOURCE.aliasListDuplicate(name));
}
nameList.add(name);
}
if (nameList.size() != rowType.getFieldCount()) {
// Position error over all column names
final SqlNode node = operands.size() == 3 ? operands.get(2) : new SqlNodeList(columnNames, SqlParserPos.sum(columnNames));
throw validator.newValidationError(node, RESOURCE.aliasListDegree(rowType.getFieldCount(), getString(rowType), nameList.size()));
}
final List<RelDataType> typeList = new ArrayList<RelDataType>();
for (RelDataTypeField field : rowType.getFieldList()) {
typeList.add(field.getType());
}
return validator.getTypeFactory().createStructType(typeList, nameList);
}
Aggregations