/**
   * INTERNAL: Build a row representation from the ADT structure field array. TopLink will then
   * build the object from the row.
   */
  public AbstractRecord buildRowFromStructure(Struct structure) throws DatabaseException {
    Object[] attributes;
    try {
      attributes = structure.getAttributes();
    } catch (java.sql.SQLException exception) {
      throw DatabaseException.sqlException(exception);
    }

    if (attributes != null) {
      for (int i = 0; i < attributes.length; i++) {
        if (attributes[i] instanceof Array) {
          attributes[i] =
              ObjectRelationalDataTypeDescriptor.buildArrayObjectFromArray(attributes[i]);
        } else if (attributes[i] instanceof Struct) {
          attributes[i] =
              ObjectRelationalDataTypeDescriptor.buildArrayObjectFromStruct(attributes[i]);
        }
      }
    }

    return buildNestedRowFromFieldValue(attributes);
  }
 @SuppressWarnings({"unchecked" /*, "rawtypes"*/})
 @Override
 public void beginPlsqlRecordField(String fieldName, int idx) {
   RecordHelper recordHelper = (RecordHelper) stac.peek();
   ObjectRelationalDataTypeDescriptor ordt =
       descriptorMap.get(recordHelper.targetTypeName().toLowerCase());
   String lFieldName = fieldName.toLowerCase();
   boolean found = false;
   Vector orderedFields = ordt.getOrderedFields();
   for (Iterator i = orderedFields.iterator(); i.hasNext(); ) {
     Object o = i.next();
     if (o instanceof DatabaseField) {
       DatabaseField field = (DatabaseField) o;
       if (field.getName().equals(lFieldName)) {
         found = true;
         break;
       }
     }
   }
   if (!found) {
     ordt.addFieldOrdering(lFieldName);
   }
 }
 @Override
 public void endPlsqlTable(String tableName, String typeDDL, String typeDropDDL) {
   ListenerHelper top = stac.pop();
   TableHelper tableHelper = (TableHelper) stac.peek();
   String tableAlias = tableHelper.targetTypeName().toLowerCase();
   ObjectRelationalDataTypeDescriptor ordt = descriptorMap.get(tableAlias);
   if (ordt == null) {
     ordt = new ObjectRelationalDataTypeDescriptor();
     ordt.descriptorIsAggregate();
     ordt.setAlias(tableHelper.tableAlias());
     ordt.setJavaClassName(tableName.toLowerCase() + COLLECTION_WRAPPER_SUFFIX);
     ordt.getQueryManager();
   }
   boolean itemsMappingFound =
       ordt.getMappingForAttributeName(ITEMS_MAPPING_ATTRIBUTE_NAME) == null ? false : true;
   if (top.isRecord()) {
     if (!itemsMappingFound) {
       ObjectArrayMapping itemsMapping = new ObjectArrayMapping();
       itemsMapping.setAttributeName(ITEMS_MAPPING_ATTRIBUTE_NAME);
       itemsMapping.setFieldName(ITEMS_MAPPING_FIELD_NAME);
       itemsMapping.setStructureName(tableHelper.targetTypeName());
       itemsMapping.setReferenceClassName(((RecordHelper) top).recordName().toLowerCase());
       ordt.addMapping(itemsMapping);
     }
     tableHelper.nestedIsComplex();
   } else {
     if (!itemsMappingFound) {
       ArrayMapping itemsMapping = new ArrayMapping();
       itemsMapping.setAttributeName(ITEMS_MAPPING_ATTRIBUTE_NAME);
       itemsMapping.setFieldName(ITEMS_MAPPING_FIELD_NAME);
       itemsMapping.useCollectionClass(ArrayList.class);
       itemsMapping.setStructureName(tableHelper.targetTypeName());
       ordt.addMapping(itemsMapping);
     }
     if (top.isTable()) {
       tableHelper.nestedIsComplex();
     }
   }
   if (!itemsMappingFound) {
     descriptorMap.put(tableAlias, ordt);
   }
 }
 @Override
 public void beginPlsqlRecord(String plsqlRecordName, String targetTypeName, int numFields) {
   RecordHelper recordHelper = new RecordHelper(plsqlRecordName, targetTypeName, numFields);
   stac.push(recordHelper);
   String recordAlias = targetTypeName.toLowerCase();
   ObjectRelationalDataTypeDescriptor ordt = descriptorMap.get(recordAlias);
   if (ordt == null) {
     ordt = new ObjectRelationalDataTypeDescriptor();
     ordt.descriptorIsAggregate();
     ordt.setAlias(recordAlias);
     ordt.setJavaClassName(plsqlRecordName.toLowerCase());
     ordt.getQueryManager();
     ordt.setStructureName(targetTypeName);
     descriptorMap.put(recordAlias, ordt);
   }
 }
 @Override
 public void endPlsqlRecordField(String fieldName, int idx) {
   ListenerHelper top = stac.pop();
   ListenerHelper listenerHelper = stac.peek();
   if (listenerHelper.isRecord()) {
     RecordHelper recordHelper = (RecordHelper) stac.peek();
     ObjectRelationalDataTypeDescriptor ordt =
         descriptorMap.get(recordHelper.targetTypeName().toLowerCase());
     String lFieldName = fieldName.toLowerCase();
     if (ordt.getMappingForAttributeName(lFieldName) == null) {
       if (top.isComplex()) {
         if (top.isTable()) {
           if (((TableHelper) top).isNestedComplex()) {
             ObjectArrayMapping objectArrayMapping = new ObjectArrayMapping();
             objectArrayMapping.setAttributeName(lFieldName);
             objectArrayMapping.setFieldName(lFieldName);
             objectArrayMapping.setStructureName(top.targetTypeName());
             objectArrayMapping.setReferenceClassName(
                 ((TableHelper) top).tableName().toLowerCase() + COLLECTION_WRAPPER_SUFFIX);
             ordt.addMapping(objectArrayMapping);
           } else {
             ArrayMapping arrayMapping = new ArrayMapping();
             arrayMapping.setAttributeName(lFieldName);
             arrayMapping.setFieldName(lFieldName);
             arrayMapping.setStructureName(top.targetTypeName());
             ordt.addMapping(arrayMapping);
           }
         } else if (top.isRecord()) {
           StructureMapping structureMapping = new StructureMapping();
           structureMapping.setAttributeName(lFieldName);
           structureMapping.setFieldName(lFieldName);
           structureMapping.setReferenceClassName(((RecordHelper) top).recordName().toLowerCase());
           ordt.addMapping(structureMapping);
         }
       } else {
         ordt.addDirectMapping(lFieldName, lFieldName);
       }
     }
   } else {
     System.identityHashCode(listenerHelper);
   }
 }
  /**
   * INTERNAL: Build and return the nested rows from the specified field value. This method allows
   * the field value to be an ARRAY containing other structures such as arrays or Struct, or direct
   * values.
   */
  public static Object buildContainerFromArray(
      Array fieldValue, ObjectRelationalDatabaseField arrayField, AbstractSession session)
      throws DatabaseException {
    if (arrayField.getType() == null) {
      return fieldValue;
    }
    Object[] objects = null;
    try {
      objects = (Object[]) fieldValue.getArray();
    } catch (java.sql.SQLException ex) {
      throw DatabaseException.sqlException(ex, session, false);
    }
    if (objects == null) {
      return null;
    }

    boolean isNestedStructure = false;
    ObjectRelationalDataTypeDescriptor ord = null;
    DatabaseField nestedType = null;
    if (arrayField != null) {
      nestedType = arrayField.getNestedTypeField();
      if ((nestedType != null) && nestedType.getSqlType() == Types.STRUCT) {
        ClassDescriptor descriptor = session.getDescriptor(nestedType.getType());
        if ((descriptor != null) && (descriptor.isObjectRelationalDataTypeDescriptor())) {
          // this is used to convert non-null objects passed through stored procedures and custom
          // SQL to structs
          ord = (ObjectRelationalDataTypeDescriptor) descriptor;
        }
      } else if ((nestedType != null) && (nestedType instanceof ObjectRelationalDatabaseField)) {
        isNestedStructure = true;
      }
    }
    // handle ARRAY conversions
    ReadObjectQuery query = new ReadObjectQuery();
    query.setSession(session);
    ContainerPolicy cp = ContainerPolicy.buildPolicyFor(arrayField.getType());
    Object container = cp.containerInstance(objects.length);
    for (int i = 0; i < objects.length; i++) {
      Object arrayValue = objects[i];
      if (arrayValue == null) {
        return null;
      }
      if (ord != null) {
        AbstractRecord nestedRow = ord.buildRowFromStructure((Struct) arrayValue);
        ClassDescriptor descriptor = ord;
        if (descriptor.hasInheritance()) {
          Class newElementClass =
              descriptor.getInheritancePolicy().classFromRow(nestedRow, session);
          if (!descriptor.getJavaClass().equals(newElementClass)) {
            descriptor = session.getDescriptor(newElementClass);
            if (descriptor == null) {
              descriptor = ord;
            }
          }
        }
        arrayValue = descriptor.getObjectBuilder().buildNewInstance();
        descriptor
            .getObjectBuilder()
            .buildAttributesIntoObject(arrayValue, nestedRow, query, null, false);
      } else if (isNestedStructure && (arrayValue instanceof Array)) {
        arrayValue =
            buildContainerFromArray(
                (Array) arrayValue, (ObjectRelationalDatabaseField) nestedType, session);
      }

      cp.addInto(arrayValue, container, session);
    }
    return container;
  }