Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Licensed to the Apache Software Foundation (ASF) under one
    * or more contributor license agreements.  See the NOTICE file
    * distributed with this work for additional information
    * regarding copyright ownership.  The ASF licenses this file
    * to you 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 at
    *
   *     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 org.apache.pig.impl.logicalLayer.schema;
  
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
The Schema class encapsulates the notion of a schema for a relational operator. A schema is a list of columns that describe the output of a relational operator. Each column in the relation is represented as a FieldSchema, a static class inside the Schema. A column by definition has an alias, a type and a possible schema (if the column is a bag or a tuple). In addition, each column in the schema has a unique auto generated name used for tracking the lineage of the column in a sequence of statements. The lineage of the column is tracked using a map of the predecessors' columns to the operators that generate the predecessor columns. The predecessor columns are the columns required in order to generate the column under consideration. Similarly, a reverse lookup of operators that generate the predecessor column to the predecessor column is maintained.
  
  
  public class Schema implements SerializableCloneable {
  
      private static final long serialVersionUID = 2L;
  
      public static class FieldSchema implements SerializableCloneable {
        
  
          private static final long serialVersionUID = 2L;

        
Alias for this field.
  
          public String alias;

        
Datatype, using codes from org.apache.pig.data.DataType.
  
          public byte type;

        
If this is a tuple itself, it can have a schema. Otherwise this field must be null.
  
          public Schema schema;

        
Canonical name. This name uniquely identifies a field throughout the query. Unlike a an alias, it cannot be changed. It will change when the field is transformed in some way (such as being used in an arithmetic expression or passed to a udf). At that point a new canonical name will be generated for the field.
  
          public String canonicalName = null;

        
Canonical namer object to generate new canonical names on request. In order to ensure unique and consistent names, across all field schema objects, the object is made static.
  
          public static final CanonicalNamer canonicalNamer = new CanonicalNamer();
          
          private static Log log = LogFactory.getLog(Schema.FieldSchema.class);

        
Constructor for any type.

Parameters:
a Alias, if known. If unknown leave null.
t Type, using codes from org.apache.pig.data.DataType.
 
         public FieldSchema(String abyte t) {
              = a;
              = t;
              = null;            
              = CanonicalNamer.getNewName();
         }

        
Constructor for tuple fields.

Parameters:
a Alias, if known. If unknown leave null.
s Schema of this tuple.
 
         public FieldSchema(String aSchema s) {
              = a;
              = .;
              = s;
              = CanonicalNamer.getNewName();
         }

        
Constructor for tuple fields.

Parameters:
a Alias, if known. If unknown leave null.
s Schema of this tuple.
t Type, using codes from org.apache.pig.data.DataType.
 
         public FieldSchema(String aSchema sbyte t)  throws FrontendException {
              = a;
              = s;
             .debug("t: " + t + " Bag: " + . + " tuple: " + .);
             
             if ((null != s) && !(DataType.isSchemaType(t))) {
                 int errCode = 1020;
                 throw new FrontendException("Only a BAG, TUPLE or MAP can have schemas. Got "
                         + DataType.findTypeName(t), errCode.);
             }
             
              = t;
              = CanonicalNamer.getNewName();
         }

        
Copy Constructor.

Parameters:
fs Source FieldSchema
 
         public FieldSchema(FieldSchema fs)  {
             if(null != fs) {
                  = fs.alias;
                 if(null != fs.schema) {
                      = new Schema(fs.schema);
                 } else {
                      = null;
                 }
                  = fs.type;
             } else {
                  = null;
                  = null;
                  = .;
             }
              = CanonicalNamer.getNewName();
         }

        
Two field schemas are equal if types and schemas are equal in all levels. In order to relax alias equivalent requirement, instead use equals(FieldSchema fschema, FieldSchema fother, boolean relaxInner, boolean relaxAlias)
 
 
         @Override
         public boolean equals(Object other) {
             if (!(other instanceof FieldSchema)) return false;
             FieldSchema otherfs = (FieldSchema)other;
 
             return FieldSchema.equals(thisotherfsfalsefalse) ;
         }
 
 
         @Override
         public int hashCode() {
             return (this. * 17)
                     + ( (==null? 0:.hashCode()) * 23 )
                     + ( (==null? 0:.hashCode()) * 29 ) ;
         }

        
Recursively compare two schemas to check if the input schema can be cast to the cast schema

Parameters:
castFs schema of the cast operator
inputFs schema of the cast input
Returns:
true or falsew!
 
         public static boolean castable(
                 Schema.FieldSchema castFs,
                 Schema.FieldSchema inputFs) {
             if(castFs == null && inputFs == null) {
                 return false;
             }
             
             if (castFs == null) {
                 return false ;
             }
     
             if (inputFs == null) {
                 return false ;
             }
             byte inputType = inputFs.type;
             byte castType = castFs.type;
     
             if (DataType.isSchemaType(castFs.type)) {
                 if(inputType == .) {
                     // good
                 } else if (inputType == castType) {
                     // Don't do the comparison if both embedded schemas are
                     // null.  That will cause Schema.equals to return false,
                     // even though we want to view that as true.
                     if (!(castFs.schema == null && inputFs.schema == null)) { 
                         // compare recursively using schema
                         if (!Schema.castable(castFs.schemainputFs.schema)) {
                             return false ;
                         }
                     }
                 } else {
                     return false;
                 }
             } else {
                 if (inputType == castType) {
                     // good
                 }
                 else if (inputType == . && (castType == .
                         || castType == . || DataType.isNumberType(castType))) {
                     // good
                 }
                 else if (DataType.isNumberType(inputType) && (castType == .
                         || castType == . || DataType.isNumberType(castType)
                         || castType == . || castType == .)) {
                     // good
                 }
                 else if (inputType == . && (castType == .
                         || castType == . || DataType.isNumberType(castType))) {
                     // good
                 }
                 else if (inputType == . && (castType == .
                         || DataType.isNumberType(castType) || castType == .
                         || castType == .)) {
                     // good
                 } 
                 else if (inputType == .) {
                     // good
                 }
                 else {
                     return false;
                 }
             }
     
             return true ;
         }

        
Compare two field schema for equality

Parameters:
fschema
fother
relaxInner If true, we don't check inner tuple schemas
relaxAlias If true, we don't check aliases
Returns:
true if FieldSchemas are equal, false otherwise
 
         public static boolean equals(FieldSchema fschema,
                                      FieldSchema fother,
                                      boolean relaxInner,
                                      boolean relaxAlias) {
             if (fschema == null) {
                 return false ;
             }
 
             if (fother == null) {
                 return false ;
             }
 
             if (fschema.type != fother.type) {
                 return false ;
             }
 
 
             if (!relaxAlias) {
                 if ( (fschema.alias == null) &&
                      (fother.alias == null) ) {
                     // good
                 }
                 else if ( (fschema.alias != null) &&
                           (fother.alias == null) ) {
                     return false ;
                 }
                 else if ( (fschema.alias == null) &&
                           (fother.alias != null) ) {
                     return false ;
                 }
                 else if (!fschema.alias.equals(fother.alias)) {
                     return false ;
                 }
             }
 
             if ( (!relaxInner) && (DataType.isSchemaType(fschema.type))) {
                 // Don't do the comparison if both embedded schemas are
                 // null.  That will cause Schema.equals to return false,
                 // even though we want to view that as true.
                 if (!(fschema.schema == null && fother.schema == null)) {
                     // compare recursively using schema
                     if (!Schema.equals(fschema.schemafother.schemafalserelaxAlias)) {
                         return false ;
                     }
                 }
             }
 
             return true ;
         }
 
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
             if ( != null) {
                 sb.append();
                 sb.append(": ");
             }
             sb.append(DataType.findTypeName());
 
             if ( != null) {
                 sb.append("(");
                 sb.append(.toString());
                 sb.append(")");
             }
 
 //            if (canonicalName != null) {
 //                sb.append(" cn: ");
 //                sb.append(canonicalName);
 //            }
 
             return sb.toString();
         }

        
Make a deep copy of this FieldSchema and return it.

Returns:
clone of the this FieldSchema.
Throws:
java.lang.CloneNotSupportedException
 
         @Override
         public FieldSchema clone() throws CloneNotSupportedException {
             // Strings are immutable, so we don't need to copy alias.  Schemas
             // are mutable so we need to make a copy.
             try {
                 FieldSchema fs = new FieldSchema(,
                     ( == null ? null : .clone()), );
                 fs.canonicalName = CanonicalNamer.getNewName();
                 return fs;
             } catch (FrontendException fe) {
                 throw new RuntimeException(
                     "Should never fail to clone a FieldSchema"fe);
             }
         }

        
Recursively prefix merge two schemas

Parameters:
otherFs the other field schema to be merged with
Returns:
the prefix merged field schema this can be null if one schema is null and allowIncompatibleTypes is true
Throws:
SchemaMergeException if they cannot be merged
 
 
         public Schema.FieldSchema mergePrefixFieldSchema(Schema.FieldSchema otherFsthrows SchemaMergeException {
             return mergePrefixFieldSchema(otherFstruefalse);
         }

        
Recursively prefix merge two schemas

Parameters:
otherFs the other field schema to be merged with
otherTakesAliasPrecedence true if aliases from the other field schema take precedence
Returns:
the prefix merged field schema this can be null if one schema is null and allowIncompatibleTypes is true
Throws:
SchemaMergeException if they cannot be merged
 
 
          public Schema.FieldSchema mergePrefixFieldSchema(Schema.FieldSchema otherFs,
                                              boolean otherTakesAliasPrecedence)
                                                  throws SchemaMergeException {
              return mergePrefixFieldSchema(otherFsotherTakesAliasPrecedencefalse);
          }
         
        
Recursively prefix merge two schemas

Parameters:
otherFs the other field schema to be merged with
otherTakesAliasPrecedence true if aliases from the other field schema take precedence
allowMergeableTypes true if "mergeable" types should be allowed. Two types are mergeable if any of the following conditions is true IN THE BELOW ORDER of checks: 1) if either one has a type null or unknown and other has a type OTHER THAN null or unknown, the result type will be the latter non null/unknown type 2) If either type is bytearray, then result type will be the other (possibly non BYTEARRAY) type 3) If current type can be cast to the other type, then the result type will be the other type
Returns:
the prefix merged field schema this can be null.
Throws:
SchemaMergeException if they cannot be merged
 
 
         public Schema.FieldSchema mergePrefixFieldSchema(Schema.FieldSchema otherFs,
                                             boolean otherTakesAliasPrecedenceboolean allowMergeableTypes)
                                                 throws SchemaMergeException {
             Schema.FieldSchema myFs = this;
             Schema.FieldSchema mergedFs = null;
             byte mergedType = .;
     
             if(null == otherFs) {
                 return myFs;
             }
 
             if(isNullOrUnknownType(myFs) && isNullOrUnknownType(otherFs)) {
                 int errCode = 1021;
                 String msg = "Type mismatch. No useful type for merging. Field Schema: " + myFs + ". Other Field Schema: " + otherFs;
                 throw new SchemaMergeException(msgerrCode.);
             } else if(myFs.type == otherFs.type) {
                 mergedType = myFs.type;
             } else if (!isNullOrUnknownType(myFs) && isNullOrUnknownType(otherFs)) {
                 mergedType = myFs.type;
             } else {
                 if (allowMergeableTypes) {
                     if (isNullOrUnknownType(myFs) && !isNullOrUnknownType(otherFs)) {
                         mergedType = otherFs.type;
                     }  else if(otherFs.type == .) {
                         // just set mergeType to myFs's type (could even be BYTEARRAY)
                         mergedType = myFs.type;
                     } else {
                         if(castable(otherFsmyFs)) {
                             mergedType = otherFs.type;
                         } else {
                             int errCode = 1022;
                             String msg = "Type mismatch for merging schema prefix. Field Schema: " + myFs + ". Other Field Schema: " + otherFs;
                             throw new SchemaMergeException(msgerrCode.);
                         }
                     }
                 } else {
                     int errCode = 1022;
                     String msg = "Type mismatch merging schema prefix. Field Schema: " + myFs + ". Other Field Schema: " + otherFs;
                     throw new SchemaMergeException(msgerrCode.);
                 }
             }
     
             String mergedAlias = mergeAlias(myFs.alias,
                                             otherFs.alias,
                                             otherTakesAliasPrecedence) ;
     
             if (!DataType.isSchemaType(mergedType)) {
                 // just normal merge
                 mergedFs = new FieldSchema(mergedAliasmergedType) ;
             }
             else {
                 Schema mergedSubSchema = null;
                 // merge inner schemas because both sides have schemas
                 if(null != myFs.schema) {
                     mergedSubSchema = myFs.schema.mergePrefixSchema(otherFs.schema,
                                                      otherTakesAliasPrecedenceallowMergeableTypes);
                 } else {
                     mergedSubSchema = otherFs.schema;
                     setSchemaDefaultType(mergedSubSchema.);
                 }
                 // create the merged field
                 try {
                     mergedFs = new FieldSchema(mergedAliasmergedSubSchemamergedType) ;
                 } catch (FrontendException fee) {
                     int errCode = 1023;
                     String msg = "Unable to create field schema.";
                     throw new SchemaMergeException(msgerrCode.fee);
                 }
             }
             return mergedFs;
         }

        
Recursively set NULL type to the specifid type

Parameters:
fs the field schema whose NULL type has to be set
t the specified type
 
         public static void setFieldSchemaDefaultType(Schema.FieldSchema fsbyte t) {
             if(null == fsreturn;
             if(. == fs.type) {
                 fs.type = t;
             }
             if(DataType.isSchemaType(fs.type)) {
                 setSchemaDefaultType(fs.schemat);
             }
         }
 
         
         private boolean isNullOrUnknownType(FieldSchema fs) {
             return (fs.type == . || fs.type == .);
         }

        
Find a field schema instance in this FieldSchema hierarchy (including "this") that matches the given canonical name.

Parameters:
canonicalName canonical name
Returns:
the FieldSchema instance found
 
 		public FieldSchema findFieldSchema(String canonicalName) {
 	        ifthis..equals(canonicalName) ) {
 	        	return this;
 	        }
 	        ifthis. != null )
 	        	return .findFieldSchemacanonicalName );
 	        return null;
         }
 
     }
 
     private List<FieldSchemamFields;
     private Map<StringFieldSchemamAliases;
     private MultiMap<StringStringmFieldSchemas;
     private static Log log = LogFactory.getLog(Schema.class);
     // In bags which have a schema with a tuple which contains
     // the fields present in it, if we access the second field (say)
     // we are actually trying to access the second field in the
     // tuple in the bag. This is currently true for two cases:
     // 1) bag constants - the schema of bag constant has a tuple
     // which internally has the actual elements
     // 2) When bags are loaded from input data, if the user 
     // specifies a schema with the "bag" type, he has to specify
     // the bag as containing a tuple with the actual elements in 
     // the schema declaration. However in both the cases above,
     // the user can still say b.i where b is the bag and i is 
     // an element in the bag's tuple schema. So in these cases,
     // the access should translate to a lookup for "i" in the 
     // tuple schema present in the bag. To indicate this, the
     // flag below is used. It is false by default because, 
     // currently we use bag as the type for relations. However 
     // the schema of a relation does NOT have a tuple fieldschema
     // with items in it. Instead, the schema directly has the 
     // field schema of the items. So for a relation "b", the 
     // above b.i access would be a direct single level access
     // of i in b's schema. This is treated as the "default" case
     private boolean twoLevelAccessRequired = false;
 
     public Schema() {
          = new ArrayList<FieldSchema>();
          = new HashMap<StringFieldSchema>();
          = new MultiMap<StringString>();
     }

    

Parameters:
fields List of field schemas that describes the fields.
 
     public Schema(List<FieldSchemafields) {
          = fields;
          = new HashMap<StringFieldSchema>(fields.size());
          = new MultiMap<StringString>();
         for (FieldSchema fs : fields) {
             if(null != fs) {
                 if (fs.alias != null) {
                     .put(fs.aliasfs);
                     .put(fs.canonicalNamefs.alias);
                 }
             }
         }
     }

    
Create a schema with only one field.

Parameters:
fieldSchema field to put in this schema.
 
     public Schema(FieldSchema fieldSchema) {
          = new ArrayList<FieldSchema>(1);
         .add(fieldSchema);
          = new HashMap<StringFieldSchema>(1);
          = new MultiMap<StringString>();
         if(null != fieldSchema) {
             if (fieldSchema.alias != null) {
                 .put(fieldSchema.aliasfieldSchema);
                 .put(fieldSchema.canonicalNamefieldSchema.alias);
             }
         }
     }

    
Copy Constructor.

Parameters:
s source schema
 
     public Schema(Schema s) {
 
         if(null != s) {
              = s.twoLevelAccessRequired;
              = new ArrayList<FieldSchema>(s.size());
              = new HashMap<StringFieldSchema>();
              = new MultiMap<StringString>();
             try {
                 for (int i = 0; i < s.size(); ++i) {
                     FieldSchema fs = new FieldSchema(s.getField(i));
                     .add(fs);
                     if(null != fs) {
                         if (fs.alias != null) {
                             .put(fs.aliasfs);
                             .put(fs.canonicalNamefs.alias);
                         }
                     }
                 }
             } catch (FrontendException pe) {
                  = new ArrayList<FieldSchema>();
                  = new HashMap<StringFieldSchema>();
                  = new MultiMap<StringString>();
             }
         } else {
              = new ArrayList<FieldSchema>();
              = new HashMap<StringFieldSchema>();
              = new MultiMap<StringString>();
         }
     }

    
Given an alias name, find the associated FieldSchema.

Parameters:
alias Alias to look up.
Returns:
FieldSchema, or null if no such alias is in this tuple.
 
     public FieldSchema getField(String aliasthrows FrontendException {
         FieldSchema fs = .get(alias);
         if(null == fs) {
             String cocoPrefix = "::" + alias;
             Map<StringIntegeraliasMatches = new HashMap<StringInteger>();
             //build the map of aliases that have cocoPrefix as the suffix
             for(String key.keySet()) {
                 if(key.endsWith(cocoPrefix)) {
                     Integer count = aliasMatches.get(key);
                     if(null == count) {
                         aliasMatches.put(key, 1);
                     } else {
                         aliasMatches.put(key, ++count);
                     }
                 }
             }
             //process the map to check if
             //1. are there multiple keys with count == 1
             //2. are there keys with count > 1 --> should never occur
             //3. if thers is a single key with count == 1 we have our match
 
             if(aliasMatches.keySet().size() == 0) {
                 return null;
             }
             if(aliasMatches.keySet().size() == 1) {
                 Object[] keys = aliasMatches.keySet().toArray();
                 String key = (String)keys[0];
                 if(aliasMatches.get(key) > 1) {
                     int errCode = 1024;
                     throw new FrontendException("Found duplicate aliases: " + keyerrCode.);
                 }
                 return .get(key);
             } else {
                 // check if the multiple aliases obtained actually
                 // point to the same field schema - then just return
                 // that field schema
                 Set<FieldSchemaset = new HashSet<FieldSchema>();
                 for (String keyaliasMatches.keySet()) {
                     set.add(.get(key));
                 }
                 if(set.size() == 1) {
                     return set.iterator().next();
                 }
                 
                 boolean hasNext = false;
                 StringBuilder sb = new StringBuilder("Found more than one match: ");
                 for (String keyaliasMatches.keySet()) {
                     if(hasNext) {
                         sb.append(", ");
                     } else {
                         hasNext = true;
                     }
                     sb.append(key);
                 }
                 int errCode = 1025;
                 throw new FrontendException(sb.toString(), errCode.);
             }
         } else {
             return fs;
         }
     }

    
    
Given an alias name, find the associated FieldSchema. If exact name is not found see if any field matches the part of the 'namespaced' alias. eg. if given alias is nm::a , and schema is (a,b). It will return FieldSchema of a. if given alias is nm::a and schema is (nm2::a, b), it will return null

Parameters:
alias Alias to look up.
Returns:
FieldSchema, or null if no such alias is in this tuple.
 
     public FieldSchema getFieldSubNameMatch(String aliasthrows FrontendException {
         if(alias == null)
             return null;
         FieldSchema fs = getField(alias);
         if(fs != null){
             return fs;
         }
         //fs is null
         final String sep = "::";
         ArrayList<FieldSchemamatchedFieldSchemas = new ArrayList<FieldSchema>();
         if(alias.contains(sep)){
             for(FieldSchema field : ) {
                 if(alias.endsWith(sep + field.alias)){
                     matchedFieldSchemas.add(field);
                 }
             }
         }
         if(matchedFieldSchemas.size() > 1){
             boolean hasNext = false;
             StringBuilder sb = new StringBuilder("Found more than one " +
             "sub alias name match: ");
             for (FieldSchema matchFs : matchedFieldSchemas) {
                 if(hasNext) {
                     sb.append(", ");
                 } else {
                     hasNext = true;
                 }
                 sb.append(matchFs.alias);
             }
             int errCode = 1116;
             throw new FrontendException(sb.toString(), errCode.);
         }else if(matchedFieldSchemas.size() == 1){
             fs = matchedFieldSchemas.get(0);
         }
 
         return fs;
     }
    
    
    
    
Given a field number, find the associated FieldSchema.

Parameters:
fieldNum Field number to look up.
Returns:
FieldSchema for this field.
Throws:
ParseException if the field number exceeds the number of fields in the tuple.
 
     public FieldSchema getField(int fieldNumthrows FrontendException {
         if (fieldNum >= .size()) {
             int errCode = 1026;
         	String detailedMsg = "Attempt to access field: " + fieldNum + " from schema: " + this;
         	String msg = "Attempt to fetch field " + fieldNum + " from schema of size " + .size();
             throw new FrontendException(msgerrCode.falsedetailedMsg);
         }
 
         return .get(fieldNum);
     }

    
Find the number of fields in the schema.

Returns:
number of fields.
 
     public int size() {
         return .size();
     }

    
Reconcile this schema with another schema. The schema being reconciled with should have the same number of columns. The use case is where a schema already exists but may not have alias and or type information. If an alias exists in this schema and a new one is given, then the new one will be used. Similarly with types, though this needs to be used carefully, as types should not be lightly changed.

Parameters:
other Schema to reconcile with.
Throws:
ParseException if this cannot be reconciled.
 
     public void reconcile(Schema otherthrows FrontendException {
 
         if (other != null) {
         
             if (other.size() != size()) {
                 int errCode = 1027;
             	String msg = "Cannot reconcile schemas with different "
                     + "sizes.  This schema has size " + size() + " other has size "
                     + "of " + other.size();
             	String detailedMsg = "Schema size mismatch. This schema: " + this + " other schema: " + other;
                 throw new FrontendException(msgerrCode.falsedetailedMsg);
             }
 
             Iterator<FieldSchemai = other.mFields.iterator();
             for (int j = 0; i.hasNext(); j++) {
                 FieldSchema otherFs = i.next();
                 FieldSchema ourFs = .get(j);
                 .debug("ourFs: " + ourFs + " otherFs: " + otherFs);
                 if (otherFs.alias != null) {
                     .debug("otherFs.alias: " + otherFs.alias);
                     if (ourFs.alias != null) {
                         .debug("Removing ourFs.alias: " + ourFs.alias);
                         .remove(ourFs.alias);
                         Collection<Stringaliases = .get(ourFs.canonicalName);
                         if (aliases != null) {
                             List<StringlistAliases = new ArrayList<String>();
                             for(String aliasaliases) {
                                 listAliases.add(alias);
                             }
                             for(String aliaslistAliases) {
                                 .debug("Removing alias " + alias + " from multimap");
                                 .remove(ourFs.canonicalNamealias);
                             }
                         }
                     }
                     ourFs.alias = otherFs.alias;
                     .debug("Setting alias to: " + otherFs.alias);
                     .put(ourFs.aliasourFs);
                     if(null != ourFs.alias) {
                         .put(ourFs.canonicalNameourFs.alias);
                     }
                 }
                 if (otherFs.type != .) {
                     ourFs.type = otherFs.type;
                     .debug("Setting type to: "
                             + DataType.findTypeName(otherFs.type));
                 }
                 if (otherFs.schema != null) {
                     ourFs.schema = otherFs.schema;
                     .debug("Setting schema to: " + otherFs.schema);
                 }
 
             }
         }
     }

    
For two schemas to be equal, they have to be deeply equal. Use Schema.equals(Schema schema, Schema other, boolean relaxInner, boolean relaxAlias) if relaxation of aliases is a requirement.
 
     @Override
     public boolean equals(Object other) {
         if (!(other instanceof Schema)) return false;
 
         Schema s = (Schema)other;
         return Schema.equals(thissfalsefalse) ;
 
     }

    
Make a deep copy of a schema.

 
     @Override
     public Schema clone() throws CloneNotSupportedException {
         Schema s = new Schema();
 
         // Build a map between old and new field schemas, so we can properly
         // construct the new alias and field schema maps.  Populate the field
         // list with copies of the existing field schemas.
         Map<FieldSchemaFieldSchemafsMap =
             new HashMap<FieldSchemaFieldSchema>(size());
         Map<StringFieldSchemafsCanonicalNameMap =
             new HashMap<StringFieldSchema>(size());
         for (FieldSchema fs : ) {
             FieldSchema copy = fs.clone();
             s.mFields.add(copy);
             fsMap.put(fscopy);
             fsCanonicalNameMap.put(fs.canonicalNamecopy);
         }
 
         // Build the aliases map
         for (String alias : .keySet()) {
             FieldSchema oldFs = .get(alias);
             assert(oldFs != null);
             FieldSchema newFs = fsMap.get(oldFs);
             assert(newFs != null);
             s.mAliases.put(aliasnewFs);
         }
 
         // Build the field schemas map
         for (String oldFsCanonicalName : .keySet()) {
             FieldSchema newFs = fsCanonicalNameMap.get(oldFsCanonicalName);
             assert(newFs != null);
             s.mFieldSchemas.put(newFs.canonicalName.get(oldFsCanonicalName));
         }
 
         s.twoLevelAccessRequired = ;
         return s;
     }
 
 
 
     static int[] primeList = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
                                41, 43, 47, 53, 59, 61, 67, 71, 73, 79,
                                83, 89, 97, 101, 103, 107, 109, 1133} ;
 
     @Override
     public int hashCode() {
         int idx = 0 ;
         int hashCode = 0 ;
         for(FieldSchema fsthis.) {
             hashCode += fs.hashCode() * ([idx % .]) ;
             idx++ ;
         }
         return hashCode ;
     }
 
     @Override
     public String toString() {
         return toIndentedString(.);
     }
 
     public String prettyPrint() {
         return toIndentedString(0);
     }
 
     private String toIndentedString(int indentLevel) {
         StringBuilder sb = new StringBuilder();
         try {
             stringifySchema(sbthis.indentLevel) ;
         }
         catch (FrontendException fee) {
             throw new RuntimeException("PROBLEM PRINTING SCHEMA")  ;
         }
         return sb.toString();
     }
 
     public static void stringifySchema(StringBuilder sbSchema schemabyte type)
             throws FrontendException {
         stringifySchema(sbschematype, 0);
     }
 
     // This is used for building up output string
     // type can only be BAG or TUPLE
     public static void stringifySchema(StringBuilder sb,
                                        Schema schema,
                                        byte type,
                                        int indentLevel)
                                             throws FrontendException{
 
         if (type == .) {
             sb.append("(") ;
         }
         else if (type == .) {
             sb.append("{") ;
         }
 
         indentLevel++;
 
         if (schema != null) {
             boolean isFirst = true ;
             for (int i=0; ischema.size() ;i++) {
 
                 if (!isFirst) {
                     sb.append(",") ;
                 }
                 else {
                     isFirst = false ;
                 }
 
                 indent(sbindentLevel);
 
                 FieldSchema fs = schema.getField(i) ;
 
                 if(fs == null) {
                     continue;
                 }
                 
                 if (fs.alias != null) {
                     sb.append(fs.alias);
                     sb.append(": ");
                 }
 
                 if (DataType.isAtomic(fs.type)) {
                     sb.append(DataType.findTypeName(fs.type)) ;
                 }
                else if ( (fs.type == .) ||
                          (fs.type == .) ) {
                    // safety net
                    if (schema != fs.schema) {
                        stringifySchema(sbfs.schemafs.typeindentLevel) ;
                    }
                    else {
                        throw new AssertionError("Schema refers to itself "
                                                 + "as inner schema") ;
                    }
                } else if (fs.type == .) {
                    sb.append(DataType.findTypeName(fs.type) + "[");
                    if (fs.schema!=null)
                        stringifySchema(sbfs.schemafs.typeindentLevel);
                    sb.append("]");
                } else {
                    sb.append(DataType.findTypeName(fs.type)) ;
                }
            }
        }
        indentLevel--;
        indent(sbindentLevel);
        if (type == .) {
            sb.append(")") ;
        }
        else if (type == .) {
            sb.append("}") ;
        }
    }

    
no-op if indentLevel is negative.
otherwise, print newline and 4*indentLevel spaces.
    private static void indent(StringBuilder sbint indentLevel) {
        if (indentLevel >= 0) {
          sb.append("\n");
        }
        while (indentLevel-- > 0) {
            sb.append("    "); // 4 spaces.
        }
    }
    public void add(FieldSchema f) {
        .add(f);
        if(null != f) {
            .put(f.canonicalNamef.alias);
            if (null != f.alias) {
                .put(f.aliasf);
            }
        }
    }

    
Given an alias, find the associated position of the field schema.

Parameters:
alias alias of the FieldSchema.
Returns:
position of the FieldSchema.
    public int getPosition(String aliasthrows FrontendException{
        return getPosition(aliasfalse);
    }


    
Given an alias, find the associated position of the field schema. It uses getFieldSubNameMatch to look for subName matches as well.

Parameters:
alias alias of the FieldSchema.
Returns:
position of the FieldSchema.
    public int getPositionSubName(String aliasthrows FrontendException{
        return getPosition(aliastrue);
    }
    
    
    private int getPosition(String aliasboolean isSubNameMatch)
    throws FrontendException {
        if(isSubNameMatch && ){
            // should not happen
            int errCode = 2248;
            String msg = "twoLevelAccessRequired==true is not supported with" +
            "and isSubNameMatch==true ";
            throw new FrontendException(msgerrCode.);
        }
        if() {
            // this is the case where "this" schema is that of
            // a bag which has just one tuple fieldschema which
            // in turn has a list of fieldschemas. The alias supplied
            // should be treated as an alias in the tuple's schema
            
            // check that indeed we only have one field schema
            // which is that of a tuple
            if(.size() != 1) {
                int errCode = 1008;
                String msg = "Expected a bag schema with a single " +
                "element of type "+ DataType.findTypeName(.) +
                " but got a bag schema with multiple elements.";
                throw new FrontendException(msgerrCode.);
            }
            Schema.FieldSchema tupleFS = .get(0);
            if(tupleFS.type != .) {
                int errCode = 1009;
                String msg = "Expected a bag schema with a single " +
                        "element of type "+ DataType.findTypeName(.) +
                        " but got an element of type " +
                        DataType.findTypeName(tupleFS.type);
                throw new FrontendException(msgerrCode.);
            }
            
            // check if the alias supplied is that of the tuple 
            // itself - then disallow it since we do not allow access
            // to the tuple itself - we only allow access to the fields
            // in the tuple
            if(alias.equals(tupleFS.alias)) {
                int errCode = 1028;
                String msg = "Access to the tuple ("alias + ") of " +
                        "the bag is disallowed. Only access to the elements of " +
                        "the tuple in the bag is allowed.";
                throw new FrontendException(msgerrCode.);
            }
            
            // all is good - get the position from the tuple's schema
            return tupleFS.schema.getPosition(alias);
        } else {
            FieldSchema fs = isSubNameMatch ? getFieldSubNameMatch(alias) : getField(alias);
    
            if (null == fs) {
                return -1;
            }
    
            .debug("fs: " + fs);
            int index = -1;
            for(int i = 0; i < .size(); ++i) {
                .debug("mFields(" + i + "): " + .get(i) + " alias: " + .get(i).);
                if(fs == .get(i)) {index = i;}
            }
    
            .debug("index: " + index);
            return index;
            //return mFields.indexOf(fs);
        }
    }
    public void addAlias(String aliasFieldSchema fs) {
        if(null != alias) {
            .put(aliasfs);
            if(null != fs) {
                .put(fs.canonicalNamealias);
            }
        }
    }
    public Set<StringgetAliases() {
        return .keySet();
    }
    public void printAliases() {
        Set<StringaliasNames = .keySet();
        for (String alias : aliasNames) {
            .debug("Schema Alias: " + alias);
        }
    }
    public List<FieldSchemagetFields() {
        return ;
    }

    
Recursively compare two schemas to check if the input schema can be cast to the cast schema

Parameters:
cast schema of the cast operator
input schema of the cast input
Returns:
true or falsew!
    public static boolean castable(Schema castSchema input) {
        // If both of them are null, they are castable
        if ((cast == null) && (input == null)) {
            return false ;
        }
        // otherwise
        if (cast == null) {
            return false ;
        }
        if (input == null) {
            return false ;
        }
        if (cast.size() > input.size()) return false;
        Iterator<FieldSchemai = cast.mFields.iterator();
        Iterator<FieldSchemaj = input.mFields.iterator();
        while (i.hasNext()) {
        //iterate only for the number of fields in cast
            FieldSchema castFs = i.next() ;
            FieldSchema inputFs = j.next() ;
            // Compare recursively using field schema
            if (!FieldSchema.castable(castFsinputFs)) {
                return false ;
            }
        }
        return true;
    }

    
Recursively compare two schemas for equality

Parameters:
schema
other
relaxInner if true, inner schemas will not be checked
relaxAlias if true, aliases will not be checked
Returns:
true if schemas are equal, false otherwise
    public static boolean equals(Schema schema,
                                 Schema other,
                                 boolean relaxInner,
                                 boolean relaxAlias) {
        // If both of them are null, they are equal
        if ((schema == null) && (other == null)) {
            return true ;
        }
        // otherwise
        if (schema == null) {