blob: 5abbd9180f2da6c5b694d3ad632b112672e4c427 [file] [log] [blame]
/*
* Copyright 2009-2013 by The Regents of the University of California
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may obtain a copy of the License from
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.uci.ics.asterix.translator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import edu.uci.ics.asterix.aql.expression.OrderedListTypeDefinition;
import edu.uci.ics.asterix.aql.expression.RecordTypeDefinition;
import edu.uci.ics.asterix.aql.expression.RecordTypeDefinition.RecordKind;
import edu.uci.ics.asterix.aql.expression.TypeDecl;
import edu.uci.ics.asterix.aql.expression.TypeExpression;
import edu.uci.ics.asterix.aql.expression.TypeReferenceExpression;
import edu.uci.ics.asterix.aql.expression.UnorderedListTypeDefinition;
import edu.uci.ics.asterix.common.annotations.IRecordFieldDataGen;
import edu.uci.ics.asterix.common.annotations.RecordDataGenAnnotation;
import edu.uci.ics.asterix.common.exceptions.AsterixException;
import edu.uci.ics.asterix.metadata.MetadataException;
import edu.uci.ics.asterix.metadata.MetadataManager;
import edu.uci.ics.asterix.metadata.MetadataTransactionContext;
import edu.uci.ics.asterix.metadata.entities.AsterixBuiltinTypeMap;
import edu.uci.ics.asterix.metadata.entities.Datatype;
import edu.uci.ics.asterix.om.types.AOrderedListType;
import edu.uci.ics.asterix.om.types.ARecordType;
import edu.uci.ics.asterix.om.types.AUnionType;
import edu.uci.ics.asterix.om.types.AUnorderedListType;
import edu.uci.ics.asterix.om.types.AbstractCollectionType;
import edu.uci.ics.asterix.om.types.BuiltinType;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.om.types.TypeSignature;
import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
public class TypeTranslator {
public static Map<TypeSignature, IAType> computeTypes(MetadataTransactionContext mdTxnCtx, TypeDecl tDec,
String defaultDataverse) throws AlgebricksException, MetadataException {
Map<TypeSignature, IAType> typeMap = new HashMap<TypeSignature, IAType>();
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes = new HashMap<String, Map<ARecordType, List<Integer>>>();
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes = new HashMap<TypeSignature, List<AbstractCollectionType>>();
Map<TypeSignature, List<TypeSignature>> incompleteTopLevelTypeReferences = new HashMap<TypeSignature, List<TypeSignature>>();
String typeDataverse = tDec.getDataverseName() == null ? defaultDataverse : tDec.getDataverseName().getValue();
firstPass(tDec, typeMap, incompleteFieldTypes, incompleteItemTypes, incompleteTopLevelTypeReferences,
typeDataverse);
secondPass(mdTxnCtx, typeMap, incompleteFieldTypes, incompleteItemTypes, incompleteTopLevelTypeReferences,
typeDataverse);
return typeMap;
}
public static Map<TypeSignature, IAType> computeTypes(MetadataTransactionContext mdTxnCtx, TypeDecl tDec,
String defaultDataverse, Map<TypeSignature, IAType> typeMap) throws AlgebricksException, MetadataException {
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes = new HashMap<String, Map<ARecordType, List<Integer>>>();
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes = new HashMap<TypeSignature, List<AbstractCollectionType>>();
Map<TypeSignature, List<TypeSignature>> incompleteTopLevelTypeReferences = new HashMap<TypeSignature, List<TypeSignature>>();
String typeDataverse = tDec.getDataverseName() == null ? defaultDataverse : tDec.getDataverseName().getValue();
firstPass(tDec, typeMap, incompleteFieldTypes, incompleteItemTypes, incompleteTopLevelTypeReferences,
typeDataverse);
secondPass(mdTxnCtx, typeMap, incompleteFieldTypes, incompleteItemTypes, incompleteTopLevelTypeReferences,
typeDataverse);
return typeMap;
}
private static Map<String, BuiltinType> builtinTypeMap = AsterixBuiltinTypeMap.getBuiltinTypes();
private static void firstPass(TypeDecl td, Map<TypeSignature, IAType> typeMap,
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes,
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes,
Map<TypeSignature, List<TypeSignature>> incompleteTopLevelTypeReferences, String typeDataverse)
throws AlgebricksException {
TypeExpression texpr = td.getTypeDef();
String tdname = td.getIdent().getValue();
if (builtinTypeMap.get(tdname) != null) {
throw new AlgebricksException("Cannot redefine builtin type " + tdname + " .");
}
TypeSignature typeSignature = new TypeSignature(typeDataverse, tdname);
try {
switch (texpr.getTypeKind()) {
case TYPEREFERENCE: {
TypeReferenceExpression tre = (TypeReferenceExpression) texpr;
IAType t = solveTypeReference(typeSignature, typeMap);
if (t != null) {
typeMap.put(typeSignature, t);
} else {
addIncompleteTopLevelTypeReference(tdname, tre, incompleteTopLevelTypeReferences, typeDataverse);
}
break;
}
case RECORD: {
RecordTypeDefinition rtd = (RecordTypeDefinition) texpr;
ARecordType recType = computeRecordType(typeSignature, rtd, typeMap, incompleteFieldTypes,
incompleteItemTypes, typeDataverse);
typeMap.put(typeSignature, recType);
break;
}
case ORDEREDLIST: {
OrderedListTypeDefinition oltd = (OrderedListTypeDefinition) texpr;
AOrderedListType olType = computeOrderedListType(typeSignature, oltd, typeMap, incompleteItemTypes,
incompleteFieldTypes, typeDataverse);
typeMap.put(typeSignature, olType);
break;
}
case UNORDEREDLIST: {
UnorderedListTypeDefinition ultd = (UnorderedListTypeDefinition) texpr;
AUnorderedListType ulType = computeUnorderedListType(typeSignature, ultd, typeMap,
incompleteItemTypes, incompleteFieldTypes, typeDataverse);
typeMap.put(typeSignature, ulType);
break;
}
default: {
throw new IllegalStateException();
}
}
} catch (AsterixException e) {
throw new AlgebricksException(e);
}
}
private static void secondPass(MetadataTransactionContext mdTxnCtx, Map<TypeSignature, IAType> typeMap,
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes,
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes,
Map<TypeSignature, List<TypeSignature>> incompleteTopLevelTypeReferences, String typeDataverse)
throws AlgebricksException, MetadataException {
// solve remaining top level references
for (TypeSignature typeSignature : incompleteTopLevelTypeReferences.keySet()) {
IAType t;// = typeMap.get(trefName);
Datatype dt = MetadataManager.INSTANCE.getDatatype(mdTxnCtx, typeSignature.getNamespace(),
typeSignature.getName());
if (dt == null) {
throw new AlgebricksException("Could not resolve type " + typeSignature);
} else
t = dt.getDatatype();
for (TypeSignature sign : incompleteTopLevelTypeReferences.get(typeSignature)) {
typeMap.put(sign, t);
}
}
// solve remaining field type references
for (String trefName : incompleteFieldTypes.keySet()) {
IAType t;// = typeMap.get(trefName);
Datatype dt = MetadataManager.INSTANCE.getDatatype(mdTxnCtx, typeDataverse, trefName);
if (dt == null) {
throw new AlgebricksException("Could not resolve type " + trefName);
} else
t = dt.getDatatype();
Map<ARecordType, List<Integer>> fieldsToFix = incompleteFieldTypes.get(trefName);
for (ARecordType recType : fieldsToFix.keySet()) {
List<Integer> positions = fieldsToFix.get(recType);
IAType[] fldTypes = recType.getFieldTypes();
for (Integer pos : positions) {
if (fldTypes[pos] == null) {
fldTypes[pos] = t;
} else { // nullable
AUnionType nullableUnion = (AUnionType) fldTypes[pos];
nullableUnion.setTypeAtIndex(t, 1);
}
}
}
}
// solve remaining item type references
for (TypeSignature typeSignature : incompleteItemTypes.keySet()) {
IAType t;// = typeMap.get(trefName);
Datatype dt = null;
if (MetadataManager.INSTANCE != null) {
dt = MetadataManager.INSTANCE.getDatatype(mdTxnCtx, typeSignature.getNamespace(),
typeSignature.getName());
if (dt == null) {
throw new AlgebricksException("Could not resolve type " + typeSignature);
}
t = dt.getDatatype();
} else {
t = typeMap.get(typeSignature);
}
for (AbstractCollectionType act : incompleteItemTypes.get(typeSignature)) {
act.setItemType(t);
}
}
}
private static AOrderedListType computeOrderedListType(TypeSignature typeSignature, OrderedListTypeDefinition oltd,
Map<TypeSignature, IAType> typeMap, Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes,
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes, String defaultDataverse)
throws AsterixException {
TypeExpression tExpr = oltd.getItemTypeExpression();
String typeName = typeSignature != null ? typeSignature.getName() : null;
AOrderedListType aolt = new AOrderedListType(null, typeName);
setCollectionItemType(tExpr, typeMap, incompleteItemTypes, incompleteFieldTypes, aolt, defaultDataverse);
return aolt;
}
private static AUnorderedListType computeUnorderedListType(TypeSignature typeSignature,
UnorderedListTypeDefinition ultd, Map<TypeSignature, IAType> typeMap,
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes,
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes, String defaulDataverse)
throws AsterixException {
TypeExpression tExpr = ultd.getItemTypeExpression();
String typeName = typeSignature != null ? typeSignature.getName() : null;
AUnorderedListType ault = new AUnorderedListType(null, typeName);
setCollectionItemType(tExpr, typeMap, incompleteItemTypes, incompleteFieldTypes, ault, defaulDataverse);
return ault;
}
private static void setCollectionItemType(TypeExpression tExpr, Map<TypeSignature, IAType> typeMap,
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes,
Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes, AbstractCollectionType act,
String defaultDataverse) throws AsterixException {
switch (tExpr.getTypeKind()) {
case ORDEREDLIST: {
OrderedListTypeDefinition oltd = (OrderedListTypeDefinition) tExpr;
IAType t = computeOrderedListType(null, oltd, typeMap, incompleteItemTypes, incompleteFieldTypes,
defaultDataverse);
act.setItemType(t);
break;
}
case UNORDEREDLIST: {
UnorderedListTypeDefinition ultd = (UnorderedListTypeDefinition) tExpr;
IAType t = computeUnorderedListType(null, ultd, typeMap, incompleteItemTypes, incompleteFieldTypes,
defaultDataverse);
act.setItemType(t);
break;
}
case RECORD: {
RecordTypeDefinition rtd = (RecordTypeDefinition) tExpr;
IAType t = computeRecordType(null, rtd, typeMap, incompleteFieldTypes, incompleteItemTypes,
defaultDataverse);
act.setItemType(t);
break;
}
case TYPEREFERENCE: {
TypeReferenceExpression tre = (TypeReferenceExpression) tExpr;
TypeSignature signature = new TypeSignature(defaultDataverse, tre.getIdent().getValue());
IAType tref = solveTypeReference(signature, typeMap);
if (tref != null) {
act.setItemType(tref);
} else {
addIncompleteCollectionTypeReference(act, tre, incompleteItemTypes, defaultDataverse);
}
break;
}
default: {
throw new IllegalStateException();
}
}
}
private static void addIncompleteCollectionTypeReference(AbstractCollectionType collType,
TypeReferenceExpression tre, Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes,
String defaultDataverse) {
String typeName = tre.getIdent().getValue();
TypeSignature typeSignature = new TypeSignature(defaultDataverse, typeName);
List<AbstractCollectionType> typeList = incompleteItemTypes.get(typeName);
if (typeList == null) {
typeList = new LinkedList<AbstractCollectionType>();
incompleteItemTypes.put(typeSignature, typeList);
}
typeList.add(collType);
}
private static void addIncompleteFieldTypeReference(ARecordType recType, int fldPosition,
TypeReferenceExpression tre, Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes) {
String typeName = tre.getIdent().getValue();
Map<ARecordType, List<Integer>> refMap = incompleteFieldTypes.get(typeName);
if (refMap == null) {
refMap = new HashMap<ARecordType, List<Integer>>();
incompleteFieldTypes.put(typeName, refMap);
}
List<Integer> typeList = refMap.get(recType);
if (typeList == null) {
typeList = new ArrayList<Integer>();
refMap.put(recType, typeList);
}
typeList.add(fldPosition);
}
private static void addIncompleteTopLevelTypeReference(String tdeclName, TypeReferenceExpression tre,
Map<TypeSignature, List<TypeSignature>> incompleteTopLevelTypeReferences, String defaultDataverse) {
String name = tre.getIdent().getValue();
TypeSignature typeSignature = new TypeSignature(defaultDataverse, name);
List<TypeSignature> refList = incompleteTopLevelTypeReferences.get(name);
if (refList == null) {
refList = new LinkedList<TypeSignature>();
incompleteTopLevelTypeReferences.put(new TypeSignature(defaultDataverse, tre.getIdent().getValue()),
refList);
}
refList.add(typeSignature);
}
private static IAType solveTypeReference(TypeSignature typeSignature, Map<TypeSignature, IAType> typeMap) {
IAType builtin = builtinTypeMap.get(typeSignature.getName());
if (builtin != null) {
return builtin;
} else {
return typeMap.get(typeSignature);
}
}
private static ARecordType computeRecordType(TypeSignature typeSignature, RecordTypeDefinition rtd,
Map<TypeSignature, IAType> typeMap, Map<String, Map<ARecordType, List<Integer>>> incompleteFieldTypes,
Map<TypeSignature, List<AbstractCollectionType>> incompleteItemTypes, String defaultDataverse)
throws AsterixException {
List<String> names = rtd.getFieldNames();
int n = names.size();
String[] fldNames = new String[n];
IAType[] fldTypes = new IAType[n];
int i = 0;
for (String s : names) {
fldNames[i++] = s;
}
boolean isOpen = rtd.getRecordKind() == RecordKind.OPEN;
ARecordType recType = new ARecordType(typeSignature == null ? null : typeSignature.getName(), fldNames,
fldTypes, isOpen);
List<IRecordFieldDataGen> fieldDataGen = rtd.getFieldDataGen();
if (fieldDataGen.size() == n) {
IRecordFieldDataGen[] rfdg = new IRecordFieldDataGen[n];
rfdg = fieldDataGen.toArray(rfdg);
recType.getAnnotations().add(new RecordDataGenAnnotation(rfdg, rtd.getUndeclaredFieldsDataGen()));
}
for (int j = 0; j < n; j++) {
TypeExpression texpr = rtd.getFieldTypes().get(j);
switch (texpr.getTypeKind()) {
case TYPEREFERENCE: {
TypeReferenceExpression tre = (TypeReferenceExpression) texpr;
TypeSignature signature = new TypeSignature(defaultDataverse, tre.getIdent().getValue());
IAType tref = solveTypeReference(signature, typeMap);
if (tref != null) {
if (!rtd.getNullableFields().get(j)) { // not nullable
fldTypes[j] = tref;
} else { // nullable
fldTypes[j] = makeUnionWithNull(null, tref);
}
} else {
addIncompleteFieldTypeReference(recType, j, tre, incompleteFieldTypes);
if (rtd.getNullableFields().get(j)) {
fldTypes[j] = makeUnionWithNull(null, null);
}
}
break;
}
case RECORD: {
RecordTypeDefinition recTypeDef2 = (RecordTypeDefinition) texpr;
IAType t2 = computeRecordType(null, recTypeDef2, typeMap, incompleteFieldTypes,
incompleteItemTypes, defaultDataverse);
if (!rtd.getNullableFields().get(j)) { // not nullable
fldTypes[j] = t2;
} else { // nullable
fldTypes[j] = makeUnionWithNull(null, t2);
}
break;
}
case ORDEREDLIST: {
OrderedListTypeDefinition oltd = (OrderedListTypeDefinition) texpr;
IAType t2 = computeOrderedListType(null, oltd, typeMap, incompleteItemTypes, incompleteFieldTypes,
defaultDataverse);
fldTypes[j] = (rtd.getNullableFields().get(j)) ? makeUnionWithNull(null, t2) : t2;
break;
}
case UNORDEREDLIST: {
UnorderedListTypeDefinition ultd = (UnorderedListTypeDefinition) texpr;
IAType t2 = computeUnorderedListType(null, ultd, typeMap, incompleteItemTypes,
incompleteFieldTypes, defaultDataverse);
fldTypes[j] = (rtd.getNullableFields().get(j)) ? makeUnionWithNull(null, t2) : t2;
break;
}
default: {
throw new IllegalStateException();
}
}
}
return recType;
}
private static AUnionType makeUnionWithNull(String unionTypeName, IAType type) {
ArrayList<IAType> unionList = new ArrayList<IAType>(2);
unionList.add(BuiltinType.ANULL);
unionList.add(type);
return new AUnionType(unionList, unionTypeName);
}
}