public List<Expression> copyDerivedExpressions(Map alreadyDone) {
   if (this.derivedExpressions == null) {
     return null;
   }
   List<Expression> derivedExpressionsCopy;
   synchronized (this) {
     derivedExpressionsCopy = new ArrayList(this.derivedExpressions);
   }
   List<Expression> result = new ArrayList(derivedExpressionsCopy.size());
   for (Expression exp : derivedExpressionsCopy) {
     result.add(exp.copiedVersionFrom(alreadyDone));
   }
   return result;
 }
 /**
  * INTERNAL: The results are *not* in a cursor, build the collection. Cache the results in
  * temporaryCachedQueryResults.
  */
 protected Object executeNonCursor() throws DatabaseException {
   Vector rows = getQueryMechanism().executeSelect();
   Object results = null;
   if (this.resultType == MAP) {
     results = getContainerPolicy().buildContainerFromVector(rows, this.session);
   } else if (this.resultType == VALUE) {
     if (!rows.isEmpty()) {
       AbstractRecord record = (AbstractRecord) rows.get(0);
       // Use get with field for XML records.
       results = record.get(record.getFields().get(0));
       if (getValueConverter() != null) {
         results = getValueConverter().convertDataValueToObjectValue(results, this.session);
       }
     }
   } else {
     int size = rows.size();
     ContainerPolicy containerPolicy = getContainerPolicy();
     results = containerPolicy.containerInstance(size);
     if (containerPolicy.shouldAddAll()) {
       if (size > 0) {
         List values = new ArrayList(size);
         for (int index = 0; index < size; index++) {
           AbstractRecord row = (AbstractRecord) rows.get(index);
           Object value = buildObject(row);
           values.add(value);
         }
         containerPolicy.addAll(values, results, this.session, rows, this);
       }
     } else {
       for (int index = 0; index < size; index++) {
         AbstractRecord row = (AbstractRecord) rows.get(index);
         Object value = buildObject(row);
         containerPolicy.addInto(value, results, this.session, row, this);
       }
     }
   }
   // Bug 6135563 - cache DataReadQuery results verbatim, as ObjectBuilder is not invoked
   cacheResult(results);
   return results;
 }
 /**
  * INTERNAL: Parses an expression to return the first non-AggregateObjectMapping expression after
  * the base ExpressionBuilder. This is used by joining and batch fetch to get the list of mappings
  * that really need to be processed (non-aggregates).
  *
  * @param aggregateMappingsEncountered - collection of aggregateObjectMapping expressions
  *     encountered in the returned expression between the first expression and the
  *     ExpressionBuilder
  * @return first non-AggregateObjectMapping expression after the base ExpressionBuilder from the
  *     fullExpression
  */
 public ObjectExpression getFirstNonAggregateExpressionAfterExpressionBuilder(
     List aggregateMappingsEncountered) {
   boolean done = false;
   ObjectExpression baseExpression = this;
   ObjectExpression prevExpression = this;
   while (!baseExpression.getBaseExpression().isExpressionBuilder() && !done) {
     baseExpression = (ObjectExpression) baseExpression.getBaseExpression();
     while (!baseExpression.isExpressionBuilder()
         && baseExpression.getMapping().isAggregateObjectMapping()) {
       aggregateMappingsEncountered.add(baseExpression.getMapping());
       baseExpression = (ObjectExpression) baseExpression.getBaseExpression();
     }
     if (baseExpression.isExpressionBuilder()) {
       done = true;
       // use the one closest to the expression builder that wasn't an aggregate
       baseExpression = prevExpression;
     } else {
       prevExpression = baseExpression;
     }
   }
   return baseExpression;
 }