}
schema = new LogicalSchema();
for(int i=0; i<outputPlans.size(); i++) {
LogicalExpression exp = (LogicalExpression)outputPlans.get(i).getSources().get(0);
byte t = exp.getType();
LogicalSchema fieldSchema = null;
String alias = null;
// for tuple and bag type, if there is projection, calculate schema of this field
if (exp instanceof ProjectExpression) {
LogicalRelationalOperator op = null;
try{
op = ((ProjectExpression)exp).findReferent(this);
}catch(Exception e) {
throw new RuntimeException(e);
}
LogicalSchema s = op.getSchema();
if (s != null) {
if (((ProjectExpression)exp).isProjectStar()) {
for(LogicalFieldSchema f: s.getFields()) {
schema.addField(f);
}
continue;
}
fieldSchema = s.getField(((ProjectExpression)exp).getColNum()).schema;
alias = s.getField(((ProjectExpression)exp).getColNum()).alias;
}
}
// if type is primitive, just add to schema
if (t != DataType.TUPLE && t != DataType.BAG) {
LogicalFieldSchema f = new LogicalSchema.LogicalFieldSchema(alias, fieldSchema, t, exp.getUid());
schema.addField(f);
continue;
}
// if flatten is set, set schema of tuple field to this schema
if (flattenFlags[i]) {
if (t == DataType.BAG) {
// if it is bag of tuples, get the schema of tuples
if (fieldSchema != null && fieldSchema.size() == 1
&& fieldSchema.getField(0).type == DataType.TUPLE) {
fieldSchema = fieldSchema.getField(0).schema;
}else {
fieldSchema = null;
}
}
if (fieldSchema != null) {
List<LogicalFieldSchema> ll = fieldSchema.getFields();
for(LogicalFieldSchema f: ll) {
LogicalFieldSchema nf = new LogicalSchema.LogicalFieldSchema(alias+"::"+f.alias, f.schema, f.type, f.uid);
schema.addField(nf);
}
} else {
schema = null;
break;
}
} else {
LogicalFieldSchema f = new LogicalSchema.LogicalFieldSchema(alias, fieldSchema, t, exp.getUid());
schema.addField(f);
}
}
return schema;
}