/**
   * INTERNAL: Return the value of the field from the row or a value holder on the query to obtain
   * the object. Check for batch + aggregation reading.
   */
  public Object valueFromRow(
      AbstractRecord row,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery query,
      AbstractSession executionSession)
      throws DatabaseException {
    Ref ref = (Ref) row.get(getField());

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

    Struct struct;
    try {
      ((DatabaseAccessor) executionSession.getAccessor()).incrementCallCount(executionSession);
      java.sql.Connection connection =
          ((DatabaseAccessor) executionSession.getAccessor()).getConnection();
      struct =
          (Struct) executionSession.getPlatform().getRefValue(ref, executionSession, connection);
    } catch (java.sql.SQLException exception) {
      throw DatabaseException.sqlException(exception, executionSession, false);
    }
    AbstractRecord targetRow =
        ((ObjectRelationalDataTypeDescriptor) getReferenceDescriptor())
            .buildRowFromStructure(struct);
    ((DatabaseAccessor) executionSession.getAccessor()).decrementCallCount();

    return getReferenceDescriptor().getObjectBuilder().buildObject(query, targetRow, joinManager);
  }
  /** INTERNAL: Build a ADT structure from the row data. */
  public Struct buildStructureFromRow(
      AbstractRecord row, AbstractSession session, java.sql.Connection connection)
      throws DatabaseException {
    Struct structure;
    boolean reconnected = false;

    try {
      if (connection == null) {
        ((DatabaseAccessor) session.getAccessor()).incrementCallCount(session);
        reconnected = true;
        connection = ((DatabaseAccessor) session.getAccessor()).getConnection();
      }

      Object[] fields = new Object[getOrderedFields().size()];
      for (int index = 0; index < getOrderedFields().size(); index++) {
        DatabaseField field = (DatabaseField) getOrderedFields().elementAt(index);
        fields[index] = row.get(field);
      }

      structure =
          session.getPlatform().createStruct(getStructureName(), fields, session, connection);
    } catch (java.sql.SQLException exception) {
      throw DatabaseException.sqlException(exception, session, false);
    } finally {
      if (reconnected) {
        ((DatabaseAccessor) session.getAccessor()).decrementCallCount();
      }
    }

    return structure;
  }
  /**
   * INTERNAL: Build and return the appropriate field value for the specified set of nested rows.
   * The database better be expecting an ARRAY. It looks like we can ignore inheritance here....
   */
  public Object buildFieldValueFromNestedRows(
      Vector nestedRows, String structureName, AbstractSession session) throws DatabaseException {
    Object[] fields = new Object[nestedRows.size()];
    java.sql.Connection connection = ((DatabaseAccessor) session.getAccessor()).getConnection();
    boolean reconnected = false;

    try {
      if (connection == null) {
        ((DatabaseAccessor) session.getAccessor()).incrementCallCount(session);
        reconnected = true;
        connection = ((DatabaseAccessor) session.getAccessor()).getConnection();
      }

      int i = 0;
      for (Enumeration stream = nestedRows.elements(); stream.hasMoreElements(); ) {
        AbstractRecord nestedRow = (AbstractRecord) stream.nextElement();
        fields[i++] = this.buildStructureFromRow(nestedRow, session, connection);
      }

      return session.getPlatform().createArray(structureName, fields, session, connection);
    } catch (java.sql.SQLException exception) {
      throw DatabaseException.sqlException(exception, session, false);
    } finally {
      if (reconnected) {
        ((DatabaseAccessor) session.getAccessor()).decrementCallCount();
      }
    }
  }
 /**
  * INTERNAL: Build the appropriate field value for the specified set of direct values. The
  * database better be expecting an ARRAY.
  */
 public Object buildFieldValueFromDirectValues(
     Vector directValues, String elementDataTypeName, AbstractSession session)
     throws DatabaseException {
   Object[] fields = Helper.arrayFromVector(directValues);
   try {
     ((DatabaseAccessor) session.getAccessor()).incrementCallCount(session);
     java.sql.Connection connection = ((DatabaseAccessor) session.getAccessor()).getConnection();
     return session.getPlatform().createArray(elementDataTypeName, fields, session, connection);
   } catch (java.sql.SQLException ex) {
     throw DatabaseException.sqlException(ex, session, false);
   } finally {
     ((DatabaseAccessor) session.getAccessor()).decrementCallCount();
   }
 }
 /**
  * INTERNAL: Build and return the field value from the specified nested database row. The database
  * better be expecting a Struct.
  */
 public Object buildFieldValueFromNestedRow(AbstractRecord nestedRow, AbstractSession session)
     throws DatabaseException {
   java.sql.Connection connection = ((DatabaseAccessor) session.getAccessor()).getConnection();
   return this.buildStructureFromRow(nestedRow, session, connection);
 }
    /**
     * Return the next sequence value. First check the global pool, if empty then allocate new
     * sequences locally.
     */
    public Object getNextValue(Sequence sequence, AbstractSession writeSession) {
      String seqName = sequence.getName();
      if (sequence.getPreallocationSize() > 1) {
        Queue sequencesForName = getPreallocationHandler().getPreallocated(seqName);
        // First grab the first sequence value without locking, a lock is only required if empty.
        Object sequenceValue = sequencesForName.poll();
        if (sequenceValue != null) {
          return sequenceValue;
        }
        // KeepLocked indicates whether the sequence lock should be kept for the whole duration of
        // this method.
        // Of course the lock should be released in any case when the method returns or throws an
        // exception.
        // This is only used if a sequence transaction was begun by the unit of work,
        // and will be committed before the unit of work commit.
        boolean keepLocked = false;
        if (!getOwnerSession().getDatasourceLogin().shouldUseExternalTransactionController()
            && !writeSession.isInTransaction()) {
          // To prevent several threads from simultaneously allocating a separate bunch of
          // sequencing numbers each. With keepLocked==true the first thread locks out others
          // until it copies the obtained sequence numbers to the global storage.
          // Note that this optimization possible only in non-jts case when there is no transaction.
          acquireLock(seqName);
          try {
            sequenceValue = sequencesForName.poll();
            if (sequenceValue != null) {
              return sequenceValue;
            }
            writeSession.beginTransaction(); // write accessor is set in begin
            keepLocked = true;
          } finally {
            if (!keepLocked) {
              releaseLock(seqName);
            }
          }
        }

        Accessor accessor;
        Vector localSequencesForName;
        if (!keepLocked) {
          writeSession.beginTransaction(); // write accessor is set in begin
        }
        try {
          accessor = writeSession.getAccessor();
          SequencingCallbackImpl seqCallbackImpl = getCallbackImpl(writeSession, accessor);
          Map localSequences = seqCallbackImpl.getPreallocatedSequenceValues();
          localSequencesForName = (Vector) localSequences.get(seqName);
          if ((localSequencesForName == null) || localSequencesForName.isEmpty()) {
            localSequencesForName = sequence.getGeneratedVector(null, writeSession);
            localSequences.put(seqName, localSequencesForName);
            logDebugLocalPreallocation(writeSession, seqName, localSequencesForName, accessor);
          }
        } catch (RuntimeException ex) {
          if (keepLocked) {
            releaseLock(seqName);
          }
          try {
            // make sure to rollback the transaction we've begun
            writeSession.rollbackTransaction();
          } catch (Exception rollbackException) {
            // ignore rollback exception
          }

          // don't eat the original exception
          throw ex;
        }

        try {
          try {
            // commitTransaction may copy preallocated sequence numbers
            // from localSequences to preallocationHandler: that happens
            // if it isn't a nested transaction, and sequencingCallback.afterCommit
            // method has been called.
            // In this case:
            // 1. localSequences corresponding to the accessor
            //    has been removed from accessorToPreallocated;
            // 2. All its members are empty (therefore localSequenceForName is empty).
            writeSession.commitTransaction();
          } catch (DatabaseException ex) {
            try {
              // make sure to rollback the transaction we've begun
              writeSession.rollbackTransaction();
            } catch (Exception rollbackException) {
              // ignore rollback exception
            }
            // don't eat the original exception
            throw ex;
          }

          if (!localSequencesForName.isEmpty()) {
            // localSeqencesForName is not empty, that means
            // sequencingCallback has not been called.
            sequenceValue = localSequencesForName.remove(0);
            return sequenceValue;
          } else {
            // localSeqencesForName is empty, that means
            // sequencingCallback has been called.
            sequenceValue = sequencesForName.poll();
            if (sequenceValue != null) {
              return sequenceValue;
            }
            return getNextValue(sequence, writeSession);
          }
        } finally {
          if (keepLocked) {
            releaseLock(seqName);
          }
        }
      } else {
        writeSession.beginTransaction();
        try {
          // preallocation size is 1 - just return the first (and only) element of the allocated
          // vector.
          Object sequenceValue = sequence.getGeneratedVector(null, writeSession).firstElement();
          writeSession.commitTransaction();
          return sequenceValue;
        } catch (RuntimeException ex) {
          try {
            // make sure to rollback the transaction we've begun
            writeSession.rollbackTransaction();
          } catch (Exception rollbackException) {
            // ignore rollback exception
          }

          // don't eat the original exception
          throw ex;
        }
      }
    }