/**
   * INTERNAL: Returns the first field from each of the owned tables, used for fine-grained
   * pessimistic locking.
   */
  protected Vector getForUpdateOfFields() {
    Vector allFields = getFields();
    int expected = getTableAliases().size();
    Vector firstFields = new Vector(expected);
    DatabaseTable lastTable = null;
    DatabaseField field = null;
    int i = 0;

    // The following loop takes O(n*m) time.  n=# of fields. m=#tables.
    // However, in the m=1 case this will take one pass only.
    // Also assuming that fields are generally sorted by table, this will
    // take O(n) time.
    // An even faster way may be to go getDescriptor().getAdditionalPrimaryKeyFields.
    while ((i < allFields.size()) && (firstFields.size() < expected)) {
      field = (DatabaseField) allFields.elementAt(i++);
      if ((lastTable == null) || !field.getTable().equals(lastTable)) {
        lastTable = field.getTable();
        int j = 0;
        while (j < firstFields.size()) {
          if (lastTable.equals(((DatabaseField) firstFields.elementAt(j)).getTable())) {
            break;
          }
          j++;
        }
        if (j == firstFields.size()) {
          firstFields.addElement(field);
        }
      }
    }
    return firstFields;
  }
  protected void buildExpectedResults() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Employee.class);

    Vector employees = (Vector) getSession().executeQuery(query);
    Vector distinctEmployees = new Vector();

    // initialize distinctEmployees
    distinctEmployees.addElement(employees.elementAt(0));

    // check employees with duplicate province and add only distinct employees to distinctEmployees
    for (int i = 1; i < employees.size(); i++) {
      boolean duplicateFound = false;

      // iterate through distinctEmployees to check for duplicate provinces, if found, employee not
      // added
      for (int j = 0; j < distinctEmployees.size(); j++) {
        if ((((Employee) employees.elementAt(i)).getAddress().getProvince())
            .equals((((Employee) distinctEmployees.elementAt(j)).getAddress().getProvince()))) {
          duplicateFound = true;
        }
      }
      if (!duplicateFound) {
        distinctEmployees.addElement(employees.elementAt(i));
      }
    }

    for (Enumeration e = distinctEmployees.elements(); e.hasMoreElements(); ) {
      Employee emp = (Employee) e.nextElement();
      Object[] result = new Object[1];
      result[0] = emp.getAddress().getProvince();
      addResult(result, null);
    }
  }
  /**
   * Return the first employee that has a long enough name for the test. If no match is found throw
   * a warning exception. See bug 223005
   *
   * @param vectorOfEmployees
   * @param minFirstNameLength
   * @param testName
   * @return
   */
  public Employee getEmployeeWithRequiredNameLength(
      Vector vectorOfEmployees, int minFirstNameLength, String testName) {
    Employee empMatch = null;
    Vector<Employee> employees = vectorOfEmployees;
    String firstName;
    StringBuffer partialFirstName;

    // Loop through the collection of employees to find one that matches our test requirements
    for (int i = 0; i < employees.size(); i++) {
      empMatch = employees.get(i);
      firstName = empMatch.getFirstName();
      // Verify length criteria
      if (firstName.length() >= minFirstNameLength) {
        // exit the for loop - return the last empMatch
        i = employees.size();
      }
    }

    // If we could not find a proper employee for testing - throw a warning
    if (null == empMatch) {
      throw new RuntimeException(
          testName
              + " Setup Failed: unable to find an Employee with firstName size of at least  "
              + minFirstNameLength);
    } else {
      return empMatch;
    }
  }
 /** PUBLIC: Set the class indicator associations. */
 public void setClassIndicatorAssociations(Vector classIndicatorAssociations) {
   setTypeIndicatorNameTranslation(new HashMap(classIndicatorAssociations.size() + 1));
   setTypeIndicatorTranslation(new HashMap((classIndicatorAssociations.size() * 2) + 1));
   for (Enumeration associationsEnum = classIndicatorAssociations.elements();
       associationsEnum.hasMoreElements(); ) {
     Association association = (Association) associationsEnum.nextElement();
     Object classValue = association.getKey();
     if (classValue instanceof Class) {
       // 904 projects will be a class type.
       addClassIndicator((Class) association.getKey(), association.getValue());
     } else {
       addClassNameIndicator((String) association.getKey(), association.getValue());
     }
   }
 }
  /**
   * INTERNAL: This method is used when computing the nested queries for batch read mappings. It
   * recurses computing the nested mapping queries.
   */
  protected void computeNestedQueriesForBatchReadExpressions(Vector batchReadExpressions) {
    for (int index = 0; index < batchReadExpressions.size(); index++) {
      ObjectExpression objectExpression = (ObjectExpression) batchReadExpressions.get(index);

      // Expression may not have been initialized.
      ExpressionBuilder builder = objectExpression.getBuilder();
      builder.setSession(getSession().getRootSession(null));
      builder.setQueryClass(getReferenceClass());

      // PERF: Cache join attribute names.
      ObjectExpression baseExpression = objectExpression;
      while (!baseExpression.getBaseExpression().isExpressionBuilder()) {
        baseExpression = (ObjectExpression) baseExpression.getBaseExpression();
      }
      this.batchReadAttributes.add(baseExpression.getName());

      // Ignore nested
      if (objectExpression.getBaseExpression().isExpressionBuilder()) {
        DatabaseMapping mapping = objectExpression.getMapping();
        if ((mapping != null) && mapping.isForeignReferenceMapping()) {
          // A nested query must be built to pass to the descriptor that looks like the real query
          // execution would.
          ReadQuery nestedQuery = ((ForeignReferenceMapping) mapping).prepareNestedBatchQuery(this);
          // Register the nested query to be used by the mapping for all the objects.
          getBatchReadMappingQueries().put(mapping, nestedQuery);
        }
      }
    }
  }
  protected void buildExpectedResults() {
    Vector employees = getSession().readAllObjects(Employee.class);

    Object[] result = new Object[1];
    result[0] = new java.math.BigDecimal(employees.size());
    addResult(result, null);
  }
 /** PUBLIC: Set a collection of the source to target query key/field associations. */
 public void setSourceToTargetQueryKeyFieldAssociations(
     Vector sourceToTargetQueryKeyFieldAssociations) {
   setSourceToTargetQueryKeyFields(
       new HashMap(sourceToTargetQueryKeyFieldAssociations.size() + 1));
   for (Enumeration associationsEnum = sourceToTargetQueryKeyFieldAssociations.elements();
       associationsEnum.hasMoreElements(); ) {
     Association association = (Association) associationsEnum.nextElement();
     Object sourceField = new DatabaseField((String) association.getKey());
     String targetQueryKey = (String) association.getValue();
     getSourceToTargetQueryKeyNames().put(sourceField, targetQueryKey);
   }
 }
  /**
   * PUBLIC: Return the foreign key field names associated with the mapping. These are only the
   * source fields that are writable.
   */
  public void setForeignKeyFieldNames(Vector fieldNames) {
    Vector fields =
        org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(
            fieldNames.size());
    for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements(); ) {
      fields.addElement(new DatabaseField((String) fieldNamesEnum.nextElement()));
    }

    setForeignKeyFields(fields);
    if (!fields.isEmpty()) {
      setIsForeignKeyRelationship(true);
    }
  }
 /** INTERNAL: Return if the attribute is specified for batch reading. */
 public boolean isAttributeBatchRead(String attributeName) {
   if (!hasBatchReadAttributes()) {
     return false;
   }
   Vector batchReadAttributeExpressions = getBatchReadAttributeExpressions();
   int size = batchReadAttributeExpressions.size();
   for (int index = 0; index < size; index++) {
     QueryKeyExpression expression = (QueryKeyExpression) batchReadAttributeExpressions.get(index);
     while (!expression.getBaseExpression().isExpressionBuilder()) {
       expression = (QueryKeyExpression) expression.getBaseExpression();
     }
     if (expression.getName().equals(attributeName)) {
       return true;
     }
   }
   return false;
 }
  public Vector getAttributeFromAll(String attributeName, Vector objects) {
    ClassDescriptor descriptor = getSession().getClassDescriptor(getReferenceClass());
    DirectToFieldMapping mapping =
        (DirectToFieldMapping) descriptor.getMappingForAttributeName(attributeName);

    Vector attributes = new Vector();
    Object currentObject;
    for (int i = 0; i < objects.size(); i++) {
      currentObject = objects.elementAt(i);
      if (currentObject.getClass() == ReportQueryResult.class) {
        attributes.addElement(((ReportQueryResult) currentObject).get(attributeName));
      } else {
        attributes.addElement(mapping.getAttributeValueFromObject(currentObject));
      }
    }
    return attributes;
  }
  /**
   * INTERNAL: Used in case outer joins should be printed in FROM clause. Each of the additional
   * tables mapped to expressions that joins it.
   */
  public Map additionalExpressionCriteriaMap() {
    if (getDescriptor() == null) {
      return null;
    }

    HashMap tablesJoinExpressions = new HashMap();
    Vector tables = getDescriptor().getTables();
    // skip the main table - start with i=1
    int tablesSize = tables.size();
    if (shouldUseOuterJoin()) {
      for (int i = 1; i < tablesSize; i++) {
        DatabaseTable table = (DatabaseTable) tables.elementAt(i);
        Expression joinExpression =
            (Expression) getDescriptor().getQueryManager().getTablesJoinExpressions().get(table);
        joinExpression = getBaseExpression().twist(joinExpression, this);
        tablesJoinExpressions.put(table, joinExpression);
      }
    }
    if (isUsingOuterJoinForMultitableInheritance()) {
      List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables();
      tablesSize = childrenTables.size();
      for (int i = 0; i < tablesSize; i++) {
        DatabaseTable table = (DatabaseTable) childrenTables.get(i);
        Expression joinExpression =
            (Expression)
                getDescriptor()
                    .getInheritancePolicy()
                    .getChildrenTablesJoinExpressions()
                    .get(table);
        joinExpression = getBaseExpression().twist(joinExpression, this);
        tablesJoinExpressions.put(table, joinExpression);
      }
    }

    return tablesJoinExpressions;
  }
  /**
   * INTERNAL This method iterates through a collection and gets the values from the objects to
   * conform in an in-memory query. Creation date: (1/19/01 1:18:27 PM)
   */
  public Object valuesFromCollection(
      Object object, AbstractSession session, int valueHolderPolicy, boolean isObjectUnregistered) {
    // in case the mapping is null - this can happen if a query key is being used
    // In this case, check for the query key and find it's mapping.
    boolean readMappingFromQueryKey = false;
    if (getMapping() == null) {
      getMappingFromQueryKey();
      readMappingFromQueryKey = true;
    }

    // For bug 2780817 get the mapping directly from the object.  In EJB 2.0
    // inheritance, each child must override mappings defined in an abstract
    // class with its own.
    DatabaseMapping mapping = this.mapping;
    ClassDescriptor descriptor = mapping.getDescriptor();
    if (descriptor.hasInheritance() && (descriptor.getJavaClass() != object.getClass())) {
      mapping =
          session
              .getDescriptor(object.getClass())
              .getObjectBuilder()
              .getMappingForAttributeName(getName());
      descriptor = mapping.getDescriptor();
    }

    // fetch group support
    if (descriptor.hasFetchGroupManager()) {
      FetchGroupManager fetchGroupManager = descriptor.getFetchGroupManager();
      if (fetchGroupManager.isPartialObject(object)
          && (!fetchGroupManager.isAttributeFetched(object, mapping.getAttributeName()))) {
        // the conforming attribute is not fetched, simply throw exception
        throw QueryException.cannotConformUnfetchedAttribute(mapping.getAttributeName());
      }
    }

    if (mapping.isDirectToFieldMapping()) {
      return ((AbstractDirectMapping) mapping).valueFromObject(object, mapping.getField(), session);
    } else if (mapping.isForeignReferenceMapping()) {
      // CR 3677 integration of a ValueHolderPolicy
      Object valueFromMapping = mapping.getAttributeValueFromObject(object);
      if (!((ForeignReferenceMapping) mapping)
          .getIndirectionPolicy()
          .objectIsInstantiated(valueFromMapping)) {
        if (valueHolderPolicy != InMemoryQueryIndirectionPolicy.SHOULD_TRIGGER_INDIRECTION) {
          // If the client wishes us to trigger the indirection then we should do so,
          // Other wise throw the exception
          throw QueryException
              .mustInstantiateValueholders(); // you should instantiate the valueholder for this to
                                              // work
        }

        // maybe we should throw this exception from the start, to save time
      }
      Object valueToIterate = mapping.getRealAttributeValueFromObject(object, session);
      UnitOfWorkImpl uow = isObjectUnregistered ? (UnitOfWorkImpl) session : null;

      // First check that object in fact is unregistered.
      // toDo: ?? Why is this commented out? Why are we supporting the unregistered thing at all?
      // Does not seem to be any public API for this, nor every used internally?
      // if (isObjectUnregistered) {
      //	isObjectUnregistered = !uow.getCloneMapping().containsKey(object);
      // }
      if (mapping.isCollectionMapping() && (valueToIterate != null)) {
        // For bug 2766379 must use the correct version of vectorFor to
        // unwrap the result same time.
        valueToIterate = mapping.getContainerPolicy().vectorFor(valueToIterate, session);

        // toDo: If the value is empty, need to support correct inner/outer join filtering
        // symantics.
        // For CR 2612601, try to partially replace the result with already
        // registered objects.
        if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) {
          Vector objectValues = (Vector) valueToIterate;
          for (int i = 0; i < objectValues.size(); i++) {
            Object original = objectValues.elementAt(i);
            Object clone =
                uow.getIdentityMapAccessorInstance()
                    .getIdentityMapManager()
                    .getFromIdentityMap(original);
            if (clone != null) {
              objectValues.setElementAt(clone, i);
            }
          }
        }

        // For CR 2612601, conforming without registering, a query could be
        // bob.get("address").get("city").equal("Ottawa"); where the address
        // has been registered and modified in the UOW, but bob has not.  Thus
        // even though bob does not point to the modified address now, it will
        // as soon as it is registered, so should point to it here.
      } else if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) {
        Object clone =
            uow.getIdentityMapAccessorInstance()
                .getIdentityMapManager()
                .getFromIdentityMap(valueToIterate);
        if (clone != null) {
          valueToIterate = clone;
        }
      }
      return valueToIterate;
    } else if (mapping.isAggregateMapping()) {
      Object aggregateValue = mapping.getAttributeValueFromObject(object);
      // Bug 3995468 - if this query key is to a mapping in an aggregate object, get the object from
      // actual mapping rather than the aggregate mapping
      while (readMappingFromQueryKey
          && mapping.isAggregateObjectMapping()
          && !((AggregateObjectMapping) mapping)
              .getReferenceClass()
              .equals(queryKey.getDescriptor().getJavaClass())) {
        mapping =
            mapping
                .getReferenceDescriptor()
                .getObjectBuilder()
                .getMappingForField(((DirectQueryKey) queryKey).getField());
        aggregateValue = mapping.getRealAttributeValueFromObject(aggregateValue, session);
      }
      return aggregateValue;
    } else {
      throw QueryException.cannotConformExpression();
    }
  }
  /** INTERNAL: Conform the result if specified. */
  protected Object conformResult(
      Object result,
      UnitOfWorkImpl unitOfWork,
      AbstractRecord arguments,
      boolean buildDirectlyFromRows) {
    if (getSelectionCriteria() != null) {
      ExpressionBuilder builder = getSelectionCriteria().getBuilder();
      builder.setSession(unitOfWork.getRootSession(null));
      builder.setQueryClass(getReferenceClass());
    }

    // If the query is redirected then the collection returned might no longer
    // correspond to the original container policy.  CR#2342-S.M.
    ContainerPolicy cp;
    if (getRedirector() != null) {
      cp = ContainerPolicy.buildPolicyFor(result.getClass());
    } else {
      cp = getContainerPolicy();
    }

    // This code is now a great deal different...  For one, registration is done
    // as part of conforming.  Also, this should only be called if one actually
    // is conforming.
    // First scan the UnitOfWork for conforming instances.
    // This will walk through the entire cache of registered objects.
    // Let p be objects from result not in the cache.
    // Let c be objects from cache.
    // Presently p intersect c = empty set, but later p subset c.
    // By checking cache now doesConform will be called p fewer times.
    Map indexedInterimResult =
        unitOfWork.scanForConformingInstances(
            getSelectionCriteria(), getReferenceClass(), arguments, this);

    Cursor cursor = null;
    // In the case of cursors just conform/register the initially read collection.
    if (cp.isCursorPolicy()) {
      cursor = (Cursor) result;
      cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class);
      // In nested UnitOfWork session might have been session of the parent.
      cursor.setSession(unitOfWork);
      result = cursor.getObjectCollection();
      // for later incremental conforming...
      cursor.setInitiallyConformingIndex(indexedInterimResult);
      cursor.setSelectionCriteriaClone(getSelectionCriteria());
      cursor.setTranslationRow(arguments);
    }

    // Now conform the result from the database.
    // Remove any deleted or changed objects that no longer conform.
    // Deletes will only work for simple queries, queries with or's or anyof's may not return
    // correct results when untriggered indirection is in the model.
    Vector fromDatabase = null;

    // When building directly from rows, one of the performance benefits
    // is that we no longer have to wrap and then unwrap the originals.
    // result is just a vector, not a container of wrapped originals.
    if (buildDirectlyFromRows) {
      Vector rows = (Vector) result;
      fromDatabase = new Vector(rows.size());
      for (int i = 0; i < rows.size(); i++) {
        Object object = rows.elementAt(i);
        // null is placed in the row collection for 1-m joining to filter duplicate rows.
        if (object != null) {
          Object clone =
              conformIndividualResult(
                  object,
                  unitOfWork,
                  arguments,
                  getSelectionCriteria(),
                  indexedInterimResult,
                  buildDirectlyFromRows);
          if (clone != null) {
            fromDatabase.addElement(clone);
          }
        }
      }
    } else {
      fromDatabase = new Vector(cp.sizeFor(result));
      AbstractSession sessionToUse = unitOfWork.getParent();
      for (Object iter = cp.iteratorFor(result); cp.hasNext(iter); ) {
        Object object = cp.next(iter, sessionToUse);
        Object clone =
            conformIndividualResult(
                object,
                unitOfWork,
                arguments,
                getSelectionCriteria(),
                indexedInterimResult,
                buildDirectlyFromRows);
        if (clone != null) {
          fromDatabase.addElement(clone);
        }
      }
    }

    // Now add the unwrapped conforming instances into an appropriate container.
    // Wrapping is done automatically.
    // Make sure a vector of exactly the right size is returned.
    Object conformedResult =
        cp.containerInstance(indexedInterimResult.size() + fromDatabase.size());
    Object eachClone;
    for (Iterator enumtr = indexedInterimResult.values().iterator(); enumtr.hasNext(); ) {
      eachClone = enumtr.next();
      cp.addInto(eachClone, conformedResult, unitOfWork);
    }
    for (Enumeration enumtr = fromDatabase.elements(); enumtr.hasMoreElements(); ) {
      eachClone = enumtr.nextElement();
      cp.addInto(eachClone, conformedResult, unitOfWork);
    }

    if (cursor != null) {
      cursor.setObjectCollection((Vector) conformedResult);

      // For nested UOW must copy all in object collection to
      // initiallyConformingIndex, as some of these could have been from
      // the parent UnitOfWork.
      if (unitOfWork.isNestedUnitOfWork()) {
        for (Enumeration enumtr = cursor.getObjectCollection().elements();
            enumtr.hasMoreElements(); ) {
          Object clone = enumtr.nextElement();
          indexedInterimResult.put(clone, clone);
        }
      }
      return cursor;
    } else {
      return conformedResult;
    }
  }
 public void verify() {
   if (results.size() != 6) {
     throw new TestErrorException(
         "The incorrect number of results was returned from a ReportQuery that included a random function.");
   }
 }
  public void test() {

    ReadAllQuery query = new ReadAllQuery();
    ScrollableCursor cursor = null;

    try {
      query.setReferenceClass(Employee.class);
      if (TYPE_SCROLL_INSENSITIVE_isSupported && CONCUR_UPDATABLE_isSupported) {
        query.useScrollableCursor(2);
      } else {
        ScrollableCursorPolicy policy = new ScrollableCursorPolicy();
        if (!TYPE_SCROLL_INSENSITIVE_isSupported) {
          policy.setResultSetType(ScrollableCursorPolicy.TYPE_SCROLL_SENSITIVE);
        }
        if (!CONCUR_UPDATABLE_isSupported) {
          policy.setResultSetConcurrency(ScrollableCursorPolicy.CONCUR_READ_ONLY);
        }
        policy.setPageSize(2);
        query.useScrollableCursor(policy);
      }
      //
      if (configuration != null) {
        ExpressionBuilder builder = new ExpressionBuilder();
        Expression exp = builder.get("salary").greaterThan(50000);
        query.setSelectionCriteria(exp);
        query.conformResultsInUnitOfWork();
      }
      cursor = (ScrollableCursor) getSession().executeQuery(query);

      try {
        // test to see if we can iterate through a list and then iterate
        // in reverse through the same list.
        int totalItems = 0;
        while (cursor.hasNext()) {
          readWithNext.addElement(cursor.next());
          totalItems++;
        }
        while (cursor.hasPrevious()) {
          readWithPrevious.addElement(cursor.previous());
          totalItems--;
        }

        cursorSuccess = (totalItems == 0);

        int size = readWithPrevious.size();
        for (int i = 0; i < readWithNext.size(); i++) {
          cursorSuccess =
              (cursorSuccess
                  && (readWithNext.elementAt(i) == readWithPrevious.elementAt((size - 1) - i)));
        }

      } catch (org.eclipse.persistence.exceptions.QueryException ex) {
        caughtException = ex;
      }

    } finally {
      if (cursor != null) {
        cursor.close();
      }
    }
  }