/** INTERNAL: */
 @Override
 public List<DatabaseField> getSelectionFields(ReadQuery query) {
   if (getDescriptor() == null) {
     DatabaseMapping mapping = getMapping();
     if (mapping != null) {
       return mapping.getSelectFields();
     }
     return new ArrayList<DatabaseField>(0);
   }
   if (descriptor.hasInheritance()
           && descriptor.getInheritancePolicy().shouldReadSubclasses()
           && (!descriptor.getInheritancePolicy().hasMultipleTableChild())
       || shouldUseOuterJoinForMultitableInheritance()) {
     // return all fields because we can.
     if (query != null && query.isObjectLevelReadQuery()) {
       return descriptor.getAllSelectionFields((ObjectLevelReadQuery) query);
     } else {
       return descriptor.getAllSelectionFields();
     }
   } else {
     if (query != null && query.isObjectLevelReadQuery()) {
       return descriptor.getSelectionFields((ObjectLevelReadQuery) query);
     } else {
       return descriptor.getSelectionFields();
     }
   }
 }
  /**
   * INTERNAL: Return the value of the reference attribute or a value holder. Check whether the
   * mapping's attribute should be optimized through batch and joining.
   */
  public Object valueFromRow(
      AbstractRecord row,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery sourceQuery,
      AbstractSession executionSession)
      throws DatabaseException {
    if (((EISDescriptor) this.getDescriptor()).getDataFormat() == EISDescriptor.XML) {
      ((XMLRecord) row).setSession(executionSession);
    }

    ReadQuery targetQuery = getSelectionQuery();
    if (!isForeignKeyRelationship) {
      // if the source query is cascading then the target query must use the same settings
      if (targetQuery.isObjectLevelReadQuery()
          && (sourceQuery.shouldCascadeAllParts()
              || (sourceQuery.shouldCascadePrivateParts() && isPrivateOwned())
              || (sourceQuery.shouldCascadeByMapping() && this.cascadeRefresh))) {
        targetQuery = (ObjectLevelReadQuery) targetQuery.clone();
        ((ObjectLevelReadQuery) targetQuery)
            .setShouldRefreshIdentityMapResult(sourceQuery.shouldRefreshIdentityMapResult());
        targetQuery.setCascadePolicy(sourceQuery.getCascadePolicy());
        // CR #4365
        targetQuery.setQueryId(sourceQuery.getQueryId());
        // For queries that have turned caching off, such as aggregate collection, leave it off.
        if (targetQuery.shouldMaintainCache()) {
          targetQuery.setShouldMaintainCache(sourceQuery.shouldMaintainCache());
        }
      }

      return getIndirectionPolicy().valueFromQuery(targetQuery, row, sourceQuery.getSession());
    } else {
      if (getIndirectionPolicy().usesIndirection()) {
        EISOneToManyQueryBasedValueHolder valueholder =
            new EISOneToManyQueryBasedValueHolder(this, targetQuery, row, sourceQuery.getSession());
        return valueholder;
      } else {
        Vector subRows = getForeignKeyRows(row);

        if (subRows == null) {
          return null;
        }

        ContainerPolicy cp = this.getContainerPolicy();
        Object results = cp.containerInstance(subRows.size());

        for (int i = 0; i < subRows.size(); i++) {
          XMLRecord subRow = (XMLRecord) subRows.elementAt(i);
          subRow.setSession(executionSession);
          Object object =
              getIndirectionPolicy().valueFromQuery(targetQuery, subRow, sourceQuery.getSession());
          if (object instanceof Collection) {
            java.util.Iterator iter = ((Collection) object).iterator();
            while (iter.hasNext()) {
              cp.addInto(iter.next(), results, executionSession);
            }
          } else if (object instanceof java.util.Map) {
            java.util.Iterator iter = ((java.util.Map) object).values().iterator();
            while (iter.hasNext()) {
              cp.addInto(iter.next(), results, executionSession);
            }
          } else {
            cp.addInto(object, results, executionSession);
          }
        }
        if (cp.sizeFor(results) == 0) {
          return null;
        }
        return results;
      }
    }
  }