Java源码示例:org.apache.calcite.sql.type.SqlTypeFamily
示例1
private SqlSingleOperandTypeChecker getChecker(RelDataType operandType) {
switch (operandType.getSqlTypeName()) {
case ARRAY:
return OperandTypes.family(SqlTypeFamily.INTEGER);
case MAP:
return OperandTypes.family(
operandType.getKeyType().getSqlTypeName().getFamily());
case ANY:
case DYNAMIC_STAR:
return OperandTypes.or(
OperandTypes.family(SqlTypeFamily.INTEGER),
OperandTypes.family(SqlTypeFamily.CHARACTER));
default:
throw new AssertionError(operandType.getSqlTypeName());
}
}
示例2
/**
* Given a {@link SqlTypeName} and nullability, create a RelDataType from the RelDataTypeFactory
*
* @param typeFactory RelDataTypeFactory used to create the RelDataType
* @param sqlTypeName the given SqlTypeName
* @param isNullable the nullability of the created RelDataType
* @return RelDataType Type of call
*/
public static RelDataType createCalciteTypeWithNullability(RelDataTypeFactory typeFactory,
SqlTypeName sqlTypeName,
boolean isNullable) {
RelDataType type;
if (sqlTypeName.getFamily() == SqlTypeFamily.INTERVAL_DAY_TIME) {
type = typeFactory.createSqlIntervalType(
new SqlIntervalQualifier(
TimeUnit.DAY,
TimeUnit.MINUTE,
SqlParserPos.ZERO));
} else if (sqlTypeName.getFamily() == SqlTypeFamily.INTERVAL_YEAR_MONTH) {
type = typeFactory.createSqlIntervalType(
new SqlIntervalQualifier(
TimeUnit.YEAR,
TimeUnit.MONTH,
SqlParserPos.ZERO));
} else if (sqlTypeName == SqlTypeName.VARCHAR) {
type = typeFactory.createSqlType(sqlTypeName, Types.MAX_VARCHAR_LENGTH);
} else {
type = typeFactory.createSqlType(sqlTypeName);
}
return typeFactory.createTypeWithNullability(type, isNullable);
}
示例3
public SqlDatePartOperator() {
super(
"DATE_PART",
SqlKind.OTHER_FUNCTION,
ReturnTypes.BIGINT_NULLABLE,
null,
OperandTypes.sequence(
"<PERIOD LITERAL>, <DATE or TIMESTAMP or INTERVAL>",
new EnumeratedListChecker(VALID_PERIODS.keySet()),
OperandTypes.or(
OperandTypes.family(SqlTypeFamily.DATE),
OperandTypes.family(SqlTypeFamily.TIMESTAMP),
OperandTypes.family(SqlTypeFamily.DATETIME),
OperandTypes.family(SqlTypeFamily.DATETIME_INTERVAL),
OperandTypes.family(SqlTypeFamily.INTERVAL_DAY_TIME),
OperandTypes.family(SqlTypeFamily.INTERVAL_YEAR_MONTH))
),
SqlFunctionCategory.SYSTEM);
}
示例4
public static List<MeasureType> validate(String fieldName, RelDataTypeFamily dataTypeFamily, List<MeasureType> measures) {
TypeHandler handle = null;
if(dataTypeFamily instanceof SqlTypeFamily) {
handle = TYPE_ALLOWANCES.get(dataTypeFamily);
}
if(handle == null) {
throw UserException.validationError()
.message("Unable to configure reflection on field %s because it was type %s.",
fieldName,
dataTypeFamily
).build(logger);
}
return handle.validate(fieldName, measures);
}
示例5
@Override
public Boolean visitCall(RexCall call) {
if (call.getOperator() == SqlStdOperatorTable.ITEM) {
final RexNode op0 = call.getOperands().get(0);
final RexNode op1 = call.getOperands().get(1);
if (op0 instanceof RexInputRef &&
op1 instanceof RexLiteral && ((RexLiteral) op1).getTypeName().getFamily() == SqlTypeFamily.CHARACTER) {
return true;
} else if (op0 instanceof RexCall &&
op1 instanceof RexLiteral && ((RexLiteral) op1).getTypeName().getFamily() == SqlTypeFamily.CHARACTER) {
return op0.accept(this);
}
}
return false;
}
示例6
private Stream<AggregateCall> toCalls(ReflectionMeasureField field) {
Optional<SqlTypeFamily> typeFamily = getSqlTypeFamily(field.getName());
if(!typeFamily.isPresent()) {
// are we silently not measuring the field ? should we catch this during validation ?
return Stream.of();
}
// for old systems, make sure we have a default measure list if one is not specificed.
List<MeasureType> measures = field.getMeasureTypeList() == null || field.getMeasureTypeList().isEmpty() ? DEFAULT_MEASURE_LIST : field.getMeasureTypeList();
List<AggregateCall> calls = new ArrayList<>();
final int inputRef = getField(field.getName()).getIndex();
int inFieldIndex = 0;
for(MeasureType t : measures) {
AggregateCall c = createMeasureFor(inputRef, inFieldIndex, typeFamily.get(), t);
if(c == null) {
continue;
}
calls.add(c);
}
return calls.stream();
}
示例7
/**
* For a particular input and type family, create the request type if it is allowed.
* @param inputRef The input of that this measure will be applied to.
* @param index The index of this measure when the collection of measure for this input field.
* @param family The type family of the field.
* @param type The type of measure to generate.
* @return An aggregate call or null if we can't create a measure of the requested type.
*/
private AggregateCall createMeasureFor(int inputRef, int index, SqlTypeFamily family, MeasureType type) {
// skip measure columns for invalid types.
if(!ReflectionValidator.getValidMeasures(family).contains(type)) {
return null;
}
switch(type) {
case APPROX_COUNT_DISTINCT:
return AggregateCall.create(HyperLogLog.HLL, false, ImmutableList.of(inputRef), -1, 1, view, null, String.format("agg-%s-%s", inputRef, index));
case COUNT:
return AggregateCall.create(SqlStdOperatorTable.COUNT, false, ImmutableList.of(inputRef), -1, 1, view, null, String.format("agg-%s-%s", inputRef, index));
case MAX:
return AggregateCall.create(SqlStdOperatorTable.MAX, false, ImmutableList.of(inputRef), -1, 1, view, null, String.format("agg-%s-%s", inputRef, index));
case MIN:
return AggregateCall.create(SqlStdOperatorTable.MIN, false, ImmutableList.of(inputRef), -1, 1, view, null, String.format("agg-%s-%s", inputRef, index));
case SUM:
return AggregateCall.create(SqlStdOperatorTable.SUM, false, ImmutableList.of(inputRef), -1, 1, view, null, String.format("agg-%s-%s", inputRef, index));
case UNKNOWN:
default:
throw new UnsupportedOperationException(type.name());
}
}
示例8
private void validateFields(List<ReflectionField> fieldList, Map<String, ViewFieldType> schemaMap, String fieldName, Boolean mustBePrimitive) {
if (fieldList == null) {
return;
}
for (ReflectionField reflectionField : fieldList) {
// A field must exist in the schema
Preconditions.checkArgument(schemaMap.containsKey(reflectionField.getName()), String.format("%s field contains a field name [%s] that does not exist in the dataset", fieldName, reflectionField.getName()));
if (mustBePrimitive) {
ViewFieldType fieldType = schemaMap.get(reflectionField.getName());
// We let ANY type pass primarily because pre-1.5 datasets may have valid fields marked as ANY.
Preconditions.checkArgument(!Arrays.asList(SqlTypeFamily.ARRAY.name(), SqlTypeFamily.MAP.name()).contains(fieldType.getTypeFamily()), String.format("%s field cannot have field [%s] of type list, map or union", fieldName, reflectionField.getName()));
}
}
}
示例9
public static boolean isTemporal(final RField field) {
final Optional<SqlTypeFamily> familyOpt = getSqlTypeFamily(field);
if (!familyOpt.isPresent()) {
return false;
}
final SqlTypeFamily family = familyOpt.get();
switch (family) {
case DATETIME:
case TIMESTAMP:
case DATE:
case TIME:
return true;
default:
return false;
}
}
示例10
/** Decision method for {@link AbstractTypeCoercion#implicitCast}. */
private void shouldCast(
RelDataType from,
SqlTypeFamily family,
RelDataType expected) {
if (family == null) {
// ROW type do not have a family.
return;
}
RelDataType castedType = ((AbstractTypeCoercion) typeCoercion).implicitCast(from, family);
boolean equals = castedType != null
&& (from.equals(castedType)
|| SqlTypeUtil.equalSansNullability(dataTypeFactory, castedType, expected)
|| expected.getSqlTypeName().getFamily().contains(castedType));
assert equals
: "Failed to cast from "
+ from.getSqlTypeName()
+ " to "
+ family;
}
示例11
/**
* If one operand in a binary operator is a DateTime type, but the other isn't,
* we should not push down the predicate
* @param call current node being evaluated
*/
private static void checkForIncompatibleDateTimeOperands(RexCall call) {
RelDataType op1 = call.getOperands().get(0).getType();
RelDataType op2 = call.getOperands().get(1).getType();
if ((SqlTypeFamily.DATETIME.contains(op1) && !SqlTypeFamily.DATETIME.contains(op2))
|| (SqlTypeFamily.DATETIME.contains(op2) && !SqlTypeFamily.DATETIME.contains(op1))
|| (SqlTypeFamily.DATE.contains(op1) && !SqlTypeFamily.DATE.contains(op2))
|| (SqlTypeFamily.DATE.contains(op2) && !SqlTypeFamily.DATE.contains(op1))
|| (SqlTypeFamily.TIMESTAMP.contains(op1) && !SqlTypeFamily.TIMESTAMP.contains(op2))
|| (SqlTypeFamily.TIMESTAMP.contains(op2) && !SqlTypeFamily.TIMESTAMP.contains(op1))
|| (SqlTypeFamily.TIME.contains(op1) && !SqlTypeFamily.TIME.contains(op2))
|| (SqlTypeFamily.TIME.contains(op2) && !SqlTypeFamily.TIME.contains(op1))) {
throw new PredicateAnalyzerException("Cannot handle " + call.getKind()
+ " expression for _id field, " + call);
}
}
示例12
public boolean builtinFunctionCoercion(
SqlCallBinding binding,
List<RelDataType> operandTypes,
List<SqlTypeFamily> expectedFamilies) {
assert binding.getOperandCount() == operandTypes.size();
if (!canImplicitTypeCast(operandTypes, expectedFamilies)) {
return false;
}
boolean coerced = false;
for (int i = 0; i < operandTypes.size(); i++) {
RelDataType implicitType = implicitCast(operandTypes.get(i), expectedFamilies.get(i));
coerced = null != implicitType
&& operandTypes.get(i) != implicitType
&& coerceOperandType(binding.getScope(), binding.getCall(), i, implicitType)
|| coerced;
}
return coerced;
}
示例13
private SqlSingleOperandTypeChecker getChecker(SqlCallBinding callBinding) {
final RelDataType operandType = callBinding.getOperandType(0);
switch (operandType.getSqlTypeName()) {
case ARRAY:
return OperandTypes.family(SqlTypeFamily.INTEGER);
case MAP:
return OperandTypes.family(
operandType.getKeyType().getSqlTypeName().getFamily());
case ROW:
return OperandTypes.CHARACTER;
case ANY:
case DYNAMIC_STAR:
return OperandTypes.or(
OperandTypes.family(SqlTypeFamily.INTEGER),
OperandTypes.family(SqlTypeFamily.CHARACTER));
default:
throw callBinding.newValidationSignatureError();
}
}
示例14
@Override
public SqlNode toSql(RexProgram program, RexNode rex) {
if (rex.getKind() == SqlKind.LITERAL) {
final RexLiteral literal = (RexLiteral) rex;
if (literal.getTypeName().getFamily() == SqlTypeFamily.CHARACTER) {
return new SqlIdentifier(RexLiteral.stringValue(literal), POS);
}
}
return super.toSql(program, rex);
}
示例15
@Override public int getNumTypeRadix(SqlTypeName typeName) {
if (typeName.getFamily() == SqlTypeFamily.NUMERIC
&& getDefaultPrecision(typeName) != -1) {
return 10;
}
return 0;
}
示例16
private static RelDataType consistentType(SqlRexContext cx,
SqlOperandTypeChecker.Consistency consistency, List<RelDataType> types) {
switch (consistency) {
case COMPARE:
if (SqlTypeUtil.areSameFamily(types)) {
// All arguments are of same family. No need for explicit casts.
return null;
}
final List<RelDataType> nonCharacterTypes = new ArrayList<>();
for (RelDataType type : types) {
if (type.getFamily() != SqlTypeFamily.CHARACTER) {
nonCharacterTypes.add(type);
}
}
if (!nonCharacterTypes.isEmpty()) {
final int typeCount = types.size();
types = nonCharacterTypes;
if (nonCharacterTypes.size() < typeCount) {
final RelDataTypeFamily family =
nonCharacterTypes.get(0).getFamily();
if (family instanceof SqlTypeFamily) {
// The character arguments might be larger than the numeric
// argument. Give ourselves some headroom.
switch ((SqlTypeFamily) family) {
case INTEGER:
case NUMERIC:
nonCharacterTypes.add(
cx.getTypeFactory().createSqlType(SqlTypeName.BIGINT));
}
}
}
}
// fall through
case LEAST_RESTRICTIVE:
return cx.getTypeFactory().leastRestrictive(types);
default:
return null;
}
}
示例17
/** Creates a SqlTimestampAddFunction. */
SqlTimestampAddFunction() {
super("TIMESTAMPADD", SqlKind.TIMESTAMP_ADD, RETURN_TYPE_INFERENCE, null,
OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.INTEGER,
SqlTypeFamily.DATETIME),
SqlFunctionCategory.TIMEDATE);
}
示例18
SqlTimestampDiffFunction() {
super("TIMESTAMPDIFF", SqlKind.TIMESTAMP_DIFF,
RETURN_TYPE_INFERENCE, null,
OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.DATETIME,
SqlTypeFamily.DATETIME),
SqlFunctionCategory.TIMEDATE);
}
示例19
public SqlJsonArrayAggAggFunction(SqlKind kind,
SqlJsonConstructorNullClause nullClause) {
super(kind + "_" + nullClause.name(), null, kind, ReturnTypes.VARCHAR_2000, null,
OperandTypes.family(SqlTypeFamily.ANY), SqlFunctionCategory.SYSTEM,
false, false, Optionality.OPTIONAL);
this.nullClause = Objects.requireNonNull(nullClause);
}
示例20
/** Creates a SqlJsonObjectAggAggFunction. */
public SqlJsonObjectAggAggFunction(SqlKind kind,
SqlJsonConstructorNullClause nullClause) {
super(kind + "_" + nullClause.name(), null, kind, ReturnTypes.VARCHAR_2000, null,
OperandTypes.family(SqlTypeFamily.CHARACTER, SqlTypeFamily.ANY),
SqlFunctionCategory.SYSTEM, false, false, Optionality.FORBIDDEN);
this.nullClause = Objects.requireNonNull(nullClause);
}
示例21
/**
* Returns whether the conversion from {@code source} to {@code target} type
* is a 'loss-less' cast, that is, a cast from which
* the original value of the field can be certainly recovered.
*
* <p>For instance, int → bigint is loss-less (as you can cast back to
* int without loss of information), but bigint → int is not loss-less.
*
* <p>The implementation of this method does not return false positives.
* However, it is not complete.
* @param source source type
* @param target target type
* @return true iff the conversion is a loss-less cast
*/
@API(since = "1.22", status = API.Status.EXPERIMENTAL)
public static boolean isLosslessCast(RelDataType source, RelDataType target) {
final SqlTypeName sourceSqlTypeName = source.getSqlTypeName();
final SqlTypeName targetSqlTypeName = target.getSqlTypeName();
// 1) Both INT numeric types
if (SqlTypeFamily.INTEGER.getTypeNames().contains(sourceSqlTypeName)
&& SqlTypeFamily.INTEGER.getTypeNames().contains(targetSqlTypeName)) {
return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0;
}
// 2) Both CHARACTER types: it depends on the precision (length)
if (SqlTypeFamily.CHARACTER.getTypeNames().contains(sourceSqlTypeName)
&& SqlTypeFamily.CHARACTER.getTypeNames().contains(targetSqlTypeName)) {
return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0
&& source.getPrecision() <= target.getPrecision();
}
// 3) From NUMERIC family to CHARACTER family: it depends on the precision/scale
if (sourceSqlTypeName.getFamily() == SqlTypeFamily.NUMERIC
&& targetSqlTypeName.getFamily() == SqlTypeFamily.CHARACTER) {
int sourceLength = source.getPrecision() + 1; // include sign
if (source.getScale() != -1 && source.getScale() != 0) {
sourceLength += source.getScale() + 1; // include decimal mark
}
return target.getPrecision() >= sourceLength;
}
// Return FALSE by default
return false;
}
示例22
public SqlJsonQueryFunction() {
super("JSON_QUERY", SqlKind.OTHER_FUNCTION,
ReturnTypes.cascade(ReturnTypes.VARCHAR_2000,
SqlTypeTransforms.FORCE_NULLABLE),
null,
OperandTypes.family(SqlTypeFamily.ANY,
SqlTypeFamily.ANY, SqlTypeFamily.ANY, SqlTypeFamily.ANY),
SqlFunctionCategory.SYSTEM);
}
示例23
private SqlSingleOperandTypeChecker getChecker(RelDataType operandType) {
switch (operandType.getSqlTypeName()) {
case ROW:
return OperandTypes.family(SqlTypeFamily.STRING);
default:
throw new AssertionError(operandType.getSqlTypeName());
}
}
示例24
/** Converts a function to a {@link org.apache.calcite.sql.SqlOperator}.
*
* <p>The {@code typeFactory} argument is technical debt; see [CALCITE-2082]
* Remove RelDataTypeFactory argument from SqlUserDefinedAggFunction
* constructor. */
private static SqlOperator toOp(RelDataTypeFactory typeFactory,
SqlIdentifier name, final Function function) {
List<RelDataType> argTypes = new ArrayList<>();
List<SqlTypeFamily> typeFamilies = new ArrayList<>();
for (FunctionParameter o : function.getParameters()) {
final RelDataType type = o.getType(typeFactory);
argTypes.add(type);
typeFamilies.add(
Util.first(type.getSqlTypeName().getFamily(), SqlTypeFamily.ANY));
}
final FamilyOperandTypeChecker typeChecker =
OperandTypes.family(typeFamilies, i ->
function.getParameters().get(i).isOptional());
final List<RelDataType> paramTypes = toSql(typeFactory, argTypes);
if (function instanceof ScalarFunction) {
return new SqlUserDefinedFunction(name, infer((ScalarFunction) function),
InferTypes.explicit(argTypes), typeChecker, paramTypes, function);
} else if (function instanceof AggregateFunction) {
return new SqlUserDefinedAggFunction(name,
infer((AggregateFunction) function), InferTypes.explicit(argTypes),
typeChecker, (AggregateFunction) function, false, false,
Optionality.FORBIDDEN, typeFactory);
} else if (function instanceof TableMacro) {
return new SqlUserDefinedTableMacro(name, ReturnTypes.CURSOR,
InferTypes.explicit(argTypes), typeChecker, paramTypes,
(TableMacro) function);
} else if (function instanceof TableFunction) {
return new SqlUserDefinedTableFunction(name, ReturnTypes.CURSOR,
InferTypes.explicit(argTypes), typeChecker, paramTypes,
(TableFunction) function);
} else {
throw new AssertionError("unknown function type " + function);
}
}
示例25
/**
* Returns whether the input is a 'loss-less' cast, that is, a cast from which
* the original value of the field can be certainly recovered.
*
* <p>For instance, int → bigint is loss-less (as you can cast back to
* int without loss of information), but bigint → int is not loss-less.
*
* <p>The implementation of this method does not return false positives.
* However, it is not complete.
*/
public static boolean isLosslessCast(RexNode node) {
if (!node.isA(SqlKind.CAST)) {
return false;
}
final RelDataType source = ((RexCall) node).getOperands().get(0).getType();
final SqlTypeName sourceSqlTypeName = source.getSqlTypeName();
final RelDataType target = node.getType();
final SqlTypeName targetSqlTypeName = target.getSqlTypeName();
// 1) Both INT numeric types
if (SqlTypeFamily.INTEGER.getTypeNames().contains(sourceSqlTypeName)
&& SqlTypeFamily.INTEGER.getTypeNames().contains(targetSqlTypeName)) {
return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0;
}
// 2) Both CHARACTER types: it depends on the precision (length)
if (SqlTypeFamily.CHARACTER.getTypeNames().contains(sourceSqlTypeName)
&& SqlTypeFamily.CHARACTER.getTypeNames().contains(targetSqlTypeName)) {
return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0
&& source.getPrecision() <= target.getPrecision();
}
// 3) From NUMERIC family to CHARACTER family: it depends on the precision/scale
if (sourceSqlTypeName.getFamily() == SqlTypeFamily.NUMERIC
&& targetSqlTypeName.getFamily() == SqlTypeFamily.CHARACTER) {
int sourceLength = source.getPrecision() + 1; // include sign
if (source.getScale() != -1 && source.getScale() != 0) {
sourceLength += source.getScale() + 1; // include decimal mark
}
return target.getPrecision() >= sourceLength;
}
// Return FALSE by default
return false;
}
示例26
public ProctimeMaterializeSqlFunction() {
super(
"PROCTIME_MATERIALIZE",
SqlKind.OTHER_FUNCTION,
ReturnTypes.cascade(
ReturnTypes.explicit(SqlTypeName.TIMESTAMP),
SqlTypeTransforms.TO_NULLABLE),
InferTypes.RETURN_TYPE,
OperandTypes.family(SqlTypeFamily.TIMESTAMP),
SqlFunctionCategory.SYSTEM);
}
示例27
public StreamRecordTimestampSqlFunction() {
super(
"STREAMRECORD_TIMESTAMP",
SqlKind.OTHER_FUNCTION,
ReturnTypes.explicit(SqlTypeName.BIGINT),
InferTypes.RETURN_TYPE,
OperandTypes.family(SqlTypeFamily.NUMERIC),
SqlFunctionCategory.SYSTEM);
}
示例28
public boolean checkSingleOperandType(
SqlCallBinding callBinding,
SqlNode node,
boolean throwOnFailure) {
if (SqlUtil.isNullLiteral(node, false)) {
if (throwOnFailure) {
throw callBinding.getValidator().newValidationError(node,
RESOURCE.nullIllegal());
} else {
return false;
}
}
RelDataType type = callBinding.getValidator().deriveType(
callBinding.getScope(),
node);
SqlTypeName typeName = type.getSqlTypeName();
// Pass type checking for operators if it's of type 'ANY'.
if (typeName.getFamily() == SqlTypeFamily.ANY) {
return true;
}
if (!family.getTypeNames().contains(typeName)) {
if (throwOnFailure) {
throw callBinding.newValidationSignatureError();
}
return false;
}
return true;
}
示例29
SqlAggFunction createCustomAggFunction(String funcName, RelDataType returnType, Class<?> customAggFuncClz) {
RelDataTypeFactory typeFactory = getCluster().getTypeFactory();
SqlIdentifier sqlIdentifier = new SqlIdentifier(funcName, new SqlParserPos(1, 1));
AggregateFunction aggFunction = AggregateFunctionImpl.create(customAggFuncClz);
List<RelDataType> argTypes = new ArrayList<RelDataType>();
List<SqlTypeFamily> typeFamilies = new ArrayList<SqlTypeFamily>();
for (FunctionParameter o : aggFunction.getParameters()) {
final RelDataType type = o.getType(typeFactory);
argTypes.add(type);
typeFamilies.add(Util.first(type.getSqlTypeName().getFamily(), SqlTypeFamily.ANY));
}
return new SqlUserDefinedAggFunction(sqlIdentifier, ReturnTypes.explicit(returnType),
InferTypes.explicit(argTypes), OperandTypes.family(typeFamilies), aggFunction, false, false,
typeFactory);
}
示例30
public RelDataType getRowType(RelDataTypeFactory factory) {
List<RelDataType> types = Lists.newArrayList();
List<String> names = Lists.newArrayList();
for (FieldType field : fields) {
names.add(field.getName());
RelDataType type;
if ( SqlTypeFamily.INTERVAL_YEAR_MONTH == field.getType().getFamily()
|| SqlTypeFamily.INTERVAL_DAY_TIME == field.getType().getFamily() ) {
type = factory.createSqlIntervalType( field.getIntervalQualifier() );
} else if (field.getType().equals(SqlTypeName.ARRAY) || field.getType().equals(SqlTypeName.MAP)) {
type = factory.createSqlType(SqlTypeName.ANY);
} else if (field.getPrecision() == null && field.getScale() == null) {
type = factory.createSqlType(field.getType());
} else if (field.getPrecision() != null && field.getScale() == null) {
type = factory.createSqlType(field.getType(), field.getPrecision());
} else {
type = factory.createSqlType(field.getType(), field.getPrecision(), field.getScale());
}
if (field.getIsNullable()) {
types.add(factory.createTypeWithNullability(type, true));
} else {
types.add(type);
}
}
return factory.createStructType(types, names);
}