@Override
  public void printSQLSelectStatement(
      DatabaseCall call, ExpressionSQLPrinter printer, SQLSelectStatement statement) {
    int max = 0;
    int firstRow = 0;
    ReadQuery query = statement.getQuery();
    if (query != null) {
      max = query.getMaxRows();
      firstRow = query.getFirstResult();
    }

    if (max <= 0 && firstRow <= 0) {
      // neither max nor firstRow is set
      super.printSQLSelectStatement(call, printer, statement);
      return;
    }
    if (max <= 0) {
      // if max row is not set use MAX_VALUE instead
      // this is done, because NewDB does not allow
      // OFFSET without LIMIT, and scrollable cursor is not supported
      // in order to support firstRows without MaxRows also MaxRow has to be set
      // this limits also the size of the result set in this case to Integer.MAX_VALUE rows
      query.setMaxRows(Integer.MAX_VALUE);
    }
    statement.setUseUniqueFieldAliases(true);
    call.setFields(statement.printSQL(printer));
    printer.printString(" LIMIT ");
    printer.printParameter(DatabaseCall.MAXROW_FIELD);
    printer.printString(" OFFSET ");
    printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD);
    call.setIgnoreFirstRowSetting(true);
    call.setIgnoreMaxResultsSetting(true);
  }
 /**
  * INTERNAL: Execute the query building the objects directly from the database result-set.
  *
  * @exception DatabaseException - an error has occurred on the database
  * @return object - the first object found or null if none.
  */
 protected Object executeObjectLevelReadQueryFromResultSet() throws DatabaseException {
   UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl) getSession();
   DatabaseAccessor accessor = (DatabaseAccessor) unitOfWork.getAccessor();
   DatabasePlatform platform = accessor.getPlatform();
   DatabaseCall call = (DatabaseCall) getCall().clone();
   call.setQuery(this);
   call.translate(this.translationRow, null, unitOfWork);
   Statement statement = null;
   ResultSet resultSet = null;
   boolean exceptionOccured = false;
   try {
     accessor.incrementCallCount(unitOfWork);
     statement = call.prepareStatement(accessor, this.translationRow, unitOfWork);
     resultSet = accessor.executeSelect(call, statement, unitOfWork);
     ResultSetMetaData metaData = resultSet.getMetaData();
     Vector results = new Vector();
     ObjectBuilder builder = this.descriptor.getObjectBuilder();
     while (resultSet.next()) {
       results.add(
           builder.buildWorkingCopyCloneFromResultSet(
               this,
               this.joinedAttributeManager,
               resultSet,
               unitOfWork,
               accessor,
               metaData,
               platform));
     }
     return results;
   } catch (SQLException exception) {
     exceptionOccured = true;
     DatabaseException commException =
         accessor.processExceptionForCommError(session, exception, call);
     if (commException != null) throw commException;
     throw DatabaseException.sqlException(exception, call, accessor, unitOfWork, false);
   } finally {
     try {
       if (resultSet != null) {
         resultSet.close();
       }
       if (statement != null) {
         accessor.releaseStatement(statement, call.getSQLString(), call, unitOfWork);
       }
     } catch (SQLException exception) {
       if (!exceptionOccured) {
         // in the case of an external connection pool the connection may be null after the
         // statement release
         // if it is null we will be unable to check the connection for a comm error and
         // therefore must return as if it was not a comm error.
         DatabaseException commException =
             accessor.processExceptionForCommError(session, exception, call);
         if (commException != null) throw commException;
         throw DatabaseException.sqlException(exception, call, accessor, session, false);
       }
     }
   }
 }
 /**
  * INTERNAL: Used by SQLCall.translate(..) The binding *must* be performed (NCHAR, NSTRING,
  * NCLOB). In these special cases the method returns a wrapper object which knows whether it
  * should be bound or appended and knows how to do that.
  */
 public Object getCustomModifyValueForCall(
     Call call, Object value, DatabaseField field, boolean shouldBind) {
   Class type = field.getType();
   if ((type != null) && isOracle9Specific(type)) {
     if (value == null) {
       return null;
     }
     if (NCHAR.equals(type) || NSTRING.equals(type)) {
       return new NTypeBindCallCustomParameter(value);
     } else if (NCLOB.equals(type)) {
       value = convertToDatabaseType(value);
       if (shouldUseLocatorForLOBWrite()) {
         if (lobValueExceedsLimit(value)) {
           ((DatabaseCall) call).addContext(field, value);
           value = new String(" ");
         }
       }
       return new NTypeBindCallCustomParameter(value);
     } else if (XMLTYPE.equals(type)) {
       return getXMLTypeFactory().createXMLTypeBindCallCustomParameter(value);
     }
   }
   return super.getCustomModifyValueForCall(call, value, field, shouldBind);
 }
 /** INTERNAL: */
 public void validationAfterDescriptorInitialization(AbstractSession session) {
   Hashtable mapped = new Hashtable();
   for (int operation = INSERT; operation <= UPDATE; operation++) {
     if ((main[operation][MAPPED] != null) && !main[operation][MAPPED].isEmpty()) {
       Iterator it = main[operation][MAPPED].iterator();
       while (it.hasNext()) {
         DatabaseField field = (DatabaseField) it.next();
         mapped.put(field, field);
       }
     }
   }
   if (!mapped.isEmpty()) {
     for (Enumeration fields = getDescriptor().getFields().elements();
         fields.hasMoreElements(); ) {
       DatabaseField fieldInDescriptor = (DatabaseField) fields.nextElement();
       DatabaseField fieldInMain = (DatabaseField) mapped.get(fieldInDescriptor);
       if (fieldInMain != null) {
         if (fieldInMain.getType() == null) {
           if (getDescriptor().isReturnTypeRequiredForReturningPolicy()) {
             session
                 .getIntegrityChecker()
                 .handleError(
                     DescriptorException.returningPolicyMappedFieldTypeNotSet(
                         fieldInMain.getName(), getDescriptor()));
           }
         } else if (isThereATypeConflict(fieldInMain, fieldInDescriptor)) {
           session
               .getIntegrityChecker()
               .handleError(
                   DescriptorException.returningPolicyAndDescriptorFieldTypeConflict(
                       fieldInMain.getName(),
                       fieldInMain.getType().getName(),
                       fieldInDescriptor.getType().getName(),
                       getDescriptor()));
         }
       }
     }
   }
   if (!(session.getDatasourcePlatform() instanceof DatabasePlatform)) {
     // don't attempt further diagnostics on non-relational platforms
     return;
   }
   WriteObjectQuery[] query = {
     getDescriptor().getQueryManager().getInsertQuery(),
     getDescriptor().getQueryManager().getUpdateQuery()
   };
   String[] queryTypeName = {"InsertObjectQuery", "UpdateObjectQuery"};
   for (int operation = INSERT; operation <= UPDATE; operation++) {
     if ((main[operation][ALL] != null) && !main[operation][ALL].isEmpty()) {
       // this operation requires some fields to be returned
       if ((query[operation] == null) || (query[operation].getDatasourceCall() == null)) {
         if (!session.getPlatform().canBuildCallWithReturning()) {
           session
               .getIntegrityChecker()
               .handleError(
                   DescriptorException.noCustomQueryForReturningPolicy(
                       queryTypeName[operation],
                       Helper.getShortClassName(session.getPlatform()),
                       getDescriptor()));
         }
       } else if (query[operation].getDatasourceCall() instanceof StoredProcedureCall) {
         // SQLCall with custom SQL calculates its outputRowFields later (in prepare() method) -
         // that's why SQLCall can't be verified here.
         DatabaseCall customCall = (DatabaseCall) query[operation].getDatasourceCall();
         Enumeration outputRowFields = customCall.getOutputRowFields().elements();
         Collection notFoundInOutputRow = createCollection();
         notFoundInOutputRow.addAll(main[operation][ALL]);
         while (outputRowFields.hasMoreElements()) {
           notFoundInOutputRow.remove(outputRowFields.nextElement());
         }
         if (!notFoundInOutputRow.isEmpty()) {
           Iterator it = notFoundInOutputRow.iterator();
           while (it.hasNext()) {
             DatabaseField field = (DatabaseField) it.next();
             session
                 .getIntegrityChecker()
                 .handleError(
                     DescriptorException.customQueryAndReturningPolicyFieldConflict(
                         field.getName(), queryTypeName[operation], getDescriptor()));
           }
         }
       }
     }
   }
 }