use of org.apache.asterix.om.types.AUnionType in project asterixdb by apache.
the class StaticTypeCastUtil method compatible.
/**
* Determine if two types are compatible
*
* @param reqType
* the required type
* @param inputType
* the input type
* @return true if the two types are compatible; false otherwise
*/
public static boolean compatible(IAType reqType, IAType inputType) {
if (reqType.getTypeTag() == ATypeTag.ANY || inputType.getTypeTag() == ATypeTag.ANY) {
return true;
}
if (reqType.getTypeTag() != ATypeTag.UNION && inputType.getTypeTag() != ATypeTag.UNION) {
if (reqType.equals(inputType)) {
return true;
} else {
return false;
}
}
Set<IAType> reqTypePossible = new HashSet<IAType>();
Set<IAType> inputTypePossible = new HashSet<IAType>();
if (reqType.getTypeTag() == ATypeTag.UNION) {
AUnionType unionType = (AUnionType) reqType;
reqTypePossible.addAll(unionType.getUnionList());
} else {
reqTypePossible.add(reqType);
}
if (inputType.getTypeTag() == ATypeTag.UNION) {
AUnionType unionType = (AUnionType) inputType;
inputTypePossible.addAll(unionType.getUnionList());
} else {
inputTypePossible.add(inputType);
}
return reqTypePossible.equals(inputTypePossible);
}
use of org.apache.asterix.om.types.AUnionType in project asterixdb by apache.
the class StaticTypeCastUtil method staticRecordTypeCast.
/**
* This method statically cast the type of records from their current type to the required type.
*
* @param func
* The record constructor expression.
* @param reqType
* The required type.
* @param inputType
* The current type.
* @param env
* The type environment.
* @throws AlgebricksException
*/
private static boolean staticRecordTypeCast(AbstractFunctionCallExpression func, ARecordType reqType, ARecordType inputType, IVariableTypeEnvironment env) throws AlgebricksException {
if (!(func.getFunctionIdentifier() == BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR || func.getFunctionIdentifier() == BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR)) {
return false;
}
IAType[] reqFieldTypes = reqType.getFieldTypes();
String[] reqFieldNames = reqType.getFieldNames();
IAType[] inputFieldTypes = inputType.getFieldTypes();
String[] inputFieldNames = inputType.getFieldNames();
int[] fieldPermutation = new int[reqFieldTypes.length];
boolean[] nullFields = new boolean[reqFieldTypes.length];
boolean[] openFields = new boolean[inputFieldTypes.length];
Arrays.fill(nullFields, false);
Arrays.fill(openFields, true);
Arrays.fill(fieldPermutation, -1);
// forward match: match from actual to required
boolean matched = false;
for (int i = 0; i < inputFieldNames.length; i++) {
String fieldName = inputFieldNames[i];
IAType fieldType = inputFieldTypes[i];
if (2 * i + 1 > func.getArguments().size()) {
// it is not a record constructor function
return false;
}
// 2*i+1 is the index of field value expression
ILogicalExpression arg = func.getArguments().get(2 * i + 1).getValue();
matched = false;
for (int j = 0; j < reqFieldNames.length; j++) {
String reqFieldName = reqFieldNames[j];
IAType reqFieldType = reqFieldTypes[j];
if (fieldName.equals(reqFieldName)) {
//type matched
if (fieldType.equals(reqFieldType)) {
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
}
break;
}
// match the optional field
if (NonTaggedFormatUtil.isOptional(reqFieldType)) {
IAType itemType = ((AUnionType) reqFieldType).getActualType();
reqFieldType = itemType;
if (fieldType.equals(BuiltinType.AMISSING) || fieldType.equals(itemType)) {
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
// rewrite record expr
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
}
break;
}
}
// delay that to runtime by calling the not-null function
if (NonTaggedFormatUtil.isOptional(fieldType)) {
IAType itemType = ((AUnionType) fieldType).getActualType();
if (reqFieldType.equals(itemType)) {
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
ScalarFunctionCallExpression notNullFunc = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CHECK_UNKNOWN));
notNullFunc.getArguments().add(new MutableObject<ILogicalExpression>(arg));
//wrap the not null function to the original function
func.getArguments().get(2 * i + 1).setValue(notNullFunc);
break;
}
}
// match the record field: need cast
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
break;
}
}
}
// the input has extra fields
if (!matched && !reqType.isOpen()) {
throw new AlgebricksException("static type mismatch: the input record includes an extra closed field " + fieldName + ":" + fieldType + "! Please check the field name and type.");
}
}
// backward match: match from required to actual
for (int i = 0; i < reqFieldNames.length; i++) {
String reqFieldName = reqFieldNames[i];
IAType reqFieldType = reqFieldTypes[i];
matched = false;
for (int j = 0; j < inputFieldNames.length; j++) {
String fieldName = inputFieldNames[j];
IAType fieldType = inputFieldTypes[j];
if (!fieldName.equals(reqFieldName)) {
continue;
}
// the entry index of fieldPermuatons is req field index
if (!openFields[j]) {
matched = true;
break;
}
// match the optional field
if (!NonTaggedFormatUtil.isOptional(reqFieldType)) {
continue;
}
IAType itemType = ((AUnionType) reqFieldType).getActualType();
if (fieldType.equals(BuiltinType.AMISSING) || fieldType.equals(itemType)) {
matched = true;
break;
}
}
if (matched) {
continue;
}
if (NonTaggedFormatUtil.isOptional(reqFieldType)) {
// add a null field
nullFields[i] = true;
} else {
// no matched field in the input for a required closed field
if (inputType.isOpen()) {
//if the input type is open, return false, give that to dynamic type cast to defer the error to the runtime
return false;
} else {
throw new AlgebricksException("static type mismatch: the input record misses a required closed field " + reqFieldName + ":" + reqFieldType + "! Please check the field name and type.");
}
}
}
List<Mutable<ILogicalExpression>> arguments = func.getArguments();
List<Mutable<ILogicalExpression>> originalArguments = new ArrayList<Mutable<ILogicalExpression>>();
originalArguments.addAll(arguments);
arguments.clear();
// re-order the closed part and fill in null fields
for (int i = 0; i < fieldPermutation.length; i++) {
int pos = fieldPermutation[i];
if (pos >= 0) {
arguments.add(originalArguments.get(2 * pos));
arguments.add(originalArguments.get(2 * pos + 1));
}
if (nullFields[i]) {
// add a null field
arguments.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(new AString(reqFieldNames[i])))));
arguments.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(ANull.NULL))));
}
}
// add the open part
for (int i = 0; i < openFields.length; i++) {
if (openFields[i]) {
arguments.add(originalArguments.get(2 * i));
Mutable<ILogicalExpression> expRef = originalArguments.get(2 * i + 1);
injectCastToRelaxType(expRef, inputFieldTypes[i], env);
arguments.add(expRef);
}
}
return true;
}
use of org.apache.asterix.om.types.AUnionType in project asterixdb by apache.
the class FieldAccessByIndexEvalFactory method createScalarEvaluator.
@Override
public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException {
return new IScalarEvaluator() {
private ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
private DataOutput out = resultStorage.getDataOutput();
private IPointable inputArg0 = new VoidPointable();
private IPointable inputArg1 = new VoidPointable();
private IScalarEvaluator eval0 = recordEvalFactory.createScalarEvaluator(ctx);
private IScalarEvaluator eval1 = fieldIndexEvalFactory.createScalarEvaluator(ctx);
private int fieldIndex;
private int fieldValueOffset;
private int fieldValueLength;
private IAType fieldValueType;
private ATypeTag fieldValueTypeTag;
/*
* inputArg0: the record
* inputArg1: the index
*
* This method outputs into IHyracksTaskContext context [field type tag (1 byte)][the field data]
*/
@Override
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
try {
resultStorage.reset();
eval0.evaluate(tuple, inputArg0);
byte[] serRecord = inputArg0.getByteArray();
int offset = inputArg0.getStartOffset();
if (serRecord[offset] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
throw new TypeMismatchException(BuiltinFunctions.FIELD_ACCESS_BY_INDEX, 0, serRecord[offset], ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
}
eval1.evaluate(tuple, inputArg1);
byte[] indexBytes = inputArg1.getByteArray();
int indexOffset = inputArg1.getStartOffset();
if (indexBytes[indexOffset] != ATypeTag.SERIALIZED_INT32_TYPE_TAG) {
throw new TypeMismatchException(BuiltinFunctions.FIELD_ACCESS_BY_INDEX, 1, indexBytes[offset], ATypeTag.SERIALIZED_INT32_TYPE_TAG);
}
fieldIndex = IntegerPointable.getInteger(indexBytes, indexOffset + 1);
fieldValueType = recordType.getFieldTypes()[fieldIndex];
fieldValueOffset = ARecordSerializerDeserializer.getFieldOffsetById(serRecord, offset, fieldIndex, nullBitmapSize, recordType.isOpen());
if (fieldValueOffset == 0) {
// the field is null, we checked the null bit map
out.writeByte(ATypeTag.SERIALIZED_NULL_TYPE_TAG);
result.set(resultStorage);
return;
}
if (fieldValueOffset < 0) {
// the field is missing, we checked the missing bit map
out.writeByte(ATypeTag.SERIALIZED_MISSING_TYPE_TAG);
result.set(resultStorage);
return;
}
if (fieldValueType.getTypeTag().equals(ATypeTag.UNION)) {
if (((AUnionType) fieldValueType).isUnknownableType()) {
fieldValueTypeTag = ((AUnionType) fieldValueType).getActualType().getTypeTag();
fieldValueLength = NonTaggedFormatUtil.getFieldValueLength(serRecord, fieldValueOffset, fieldValueTypeTag, false);
out.writeByte(fieldValueTypeTag.serialize());
} else {
// union .. the general case
throw new NotImplementedException();
}
} else {
fieldValueTypeTag = fieldValueType.getTypeTag();
fieldValueLength = NonTaggedFormatUtil.getFieldValueLength(serRecord, fieldValueOffset, fieldValueTypeTag, false);
out.writeByte(fieldValueTypeTag.serialize());
}
out.write(serRecord, fieldValueOffset, fieldValueLength);
result.set(resultStorage);
} catch (IOException e) {
throw new HyracksDataException(e);
} catch (AsterixException e) {
throw new HyracksDataException(e);
}
}
};
}
use of org.apache.asterix.om.types.AUnionType in project asterixdb by apache.
the class MetadataNode method getNestedComplexDatatypeNamesForThisDatatype.
private List<String> getNestedComplexDatatypeNamesForThisDatatype(JobId jobId, String dataverseName, String datatypeName) throws MetadataException, RemoteException {
//Return all field types that aren't builtin types
Datatype parentType = getDatatype(jobId, dataverseName, datatypeName);
List<IAType> subTypes = null;
if (parentType.getDatatype().getTypeTag() == ATypeTag.OBJECT) {
ARecordType recType = (ARecordType) parentType.getDatatype();
subTypes = Arrays.asList(recType.getFieldTypes());
} else if (parentType.getDatatype().getTypeTag() == ATypeTag.UNION) {
AUnionType recType = (AUnionType) parentType.getDatatype();
subTypes = recType.getUnionList();
}
List<String> nestedTypes = new ArrayList<>();
if (subTypes != null) {
for (IAType subType : subTypes) {
if (!(subType instanceof BuiltinType)) {
nestedTypes.add(subType.getTypeName());
}
}
}
return nestedTypes;
}
use of org.apache.asterix.om.types.AUnionType in project asterixdb by apache.
the class JSONDeserializerForTypesTest method test.
@Test
public void test() throws Exception {
// Tests a record type with primitive types.
String[] fieldNames = { "a1", "a2", "a3" };
IAType[] fieldTypes = { BuiltinType.ASTRING, BuiltinType.AINT16, BuiltinType.ABITARRAY };
ARecordType recordType = new ARecordType("ARecord", fieldNames, fieldTypes, true);
Assert.assertEquals(recordType, JSONDeserializerForTypes.convertFromJSON(recordType.toJSON()));
// Tests a record type with a nested record type.
String[] fieldNames2 = { "a1", "a2" };
IAType[] fieldTypes2 = { BuiltinType.ABOOLEAN, recordType };
ARecordType recordType2 = new ARecordType("ARecord2", fieldNames2, fieldTypes2, true);
Assert.assertEquals(recordType2, JSONDeserializerForTypes.convertFromJSON(recordType2.toJSON()));
// Tests a record type with a union type.
String[] fieldNames3 = { "a1", "a2" };
List<IAType> unionTypes = new ArrayList<IAType>();
unionTypes.add(BuiltinType.ADURATION);
unionTypes.add(recordType2);
AUnionType unionType = new AUnionType(unionTypes, "union");
IAType[] fieldTypes3 = { BuiltinType.ABOOLEAN, unionType };
ARecordType recordType3 = new ARecordType("ARecord3", fieldNames3, fieldTypes3, true);
Assert.assertEquals(recordType3, JSONDeserializerForTypes.convertFromJSON(recordType3.toJSON()));
// Tests a record type with an ordered list.
String[] fieldNames4 = { "a1", "a2" };
IAType[] fieldTypes4 = { BuiltinType.ABOOLEAN, new AOrderedListType(BuiltinType.ADATETIME, "list") };
ARecordType recordType4 = new ARecordType("ARecord4", fieldNames4, fieldTypes4, false);
Assert.assertEquals(recordType4, JSONDeserializerForTypes.convertFromJSON(recordType4.toJSON()));
// Tests a record type with an unordered list.
String[] fieldNames5 = { "a1", "a2" };
IAType[] fieldTypes5 = { BuiltinType.ABOOLEAN, new AUnorderedListType(recordType2, "list") };
ARecordType recordType5 = new ARecordType("ARecord5", fieldNames5, fieldTypes5, false);
Assert.assertEquals(recordType5, JSONDeserializerForTypes.convertFromJSON(recordType5.toJSON()));
}
Aggregations