public ProjectionMap getProjectionMap() {
if(mIsProjectionMapComputed) return mProjectionMap;
mIsProjectionMapComputed = true;
Schema outputSchema;
try {
outputSchema = getSchema();
} catch (FrontendException fee) {
mProjectionMap = null;
return mProjectionMap;
}
if(outputSchema == null) {
mProjectionMap = null;
return mProjectionMap;
}
List<LogicalOperator> predecessors = (ArrayList<LogicalOperator>)mPlan.getPredecessors(this);
if(predecessors == null) {
mProjectionMap = null;
return mProjectionMap;
}
LogicalOperator predecessor = predecessors.get(0);
Schema inputSchema;
try {
inputSchema = predecessor.getSchema();
} catch (FrontendException fee) {
mProjectionMap = null;
return mProjectionMap;
}
List<LogicalPlan> foreachPlans = getForEachPlans();
List<Boolean> flattenList = getFlatten();
MultiMap<Integer, ProjectionMap.Column> mapFields = new MultiMap<Integer, ProjectionMap.Column>();
List<Integer> addedFields = new ArrayList<Integer>();
int outputColumn = 0;
for(int i = 0; i < foreachPlans.size(); ++i) {
LogicalPlan foreachPlan = foreachPlans.get(i);
List<LogicalOperator> leaves = foreachPlan.getLeaves();
if(leaves == null || leaves.size() > 1) {
mProjectionMap = null;
return mProjectionMap;
}
int inputColumn = -1;
boolean mapped = false;
LOCast cast = null;
if(leaves.get(0) instanceof LOProject || leaves.get(0) instanceof LOCast) {
//find out if this project is a chain of projects
Pair<LOProject, LOCast> pair = LogicalPlan.chainOfProjects(foreachPlan);
if (pair != null) {
LOProject topProject = pair.first;
cast = pair.second;
if (topProject != null) {
inputColumn = topProject.getCol();
mapped = true;
}
}
}
Schema.FieldSchema leafFS;
try {
leafFS = ((ExpressionOperator)leaves.get(0)).getFieldSchema();
} catch (FrontendException fee) {
mProjectionMap = null;
return mProjectionMap;
}
if(leafFS == null) {
mProjectionMap = null;
return mProjectionMap;
}
if(flattenList.get(i)) {
Schema innerSchema = leafFS.schema;
if(innerSchema != null) {
if(innerSchema.isTwoLevelAccessRequired()) {
// this is the case where the schema is that of
// a bag which has just one tuple fieldschema which
// in turn has a list of fieldschemas. The schema
// after flattening would consist of the fieldSchemas
// present in the tuple
// check that indeed we only have one field schema
// which is that of a tuple
if(innerSchema.getFields().size() != 1) {
mProjectionMap = null;
return mProjectionMap;
}
Schema.FieldSchema tupleFS;
try {
tupleFS = innerSchema.getField(0);
} catch (FrontendException fee) {
mProjectionMap = null;
return mProjectionMap;
}
if(tupleFS.type != DataType.TUPLE) {
mProjectionMap = null;
return mProjectionMap;
}
innerSchema = tupleFS.schema;
}
//innerSchema could be modified and hence the second check
if(innerSchema != null) {
for(int j = 0; j < innerSchema.size(); ++j) {
if(mapped) {
//map each flattened column to the original column
if (cast != null) {
mapFields.put(outputColumn++,
new ProjectionMap.Column(