/** Convenient method to just calculate the result count of a given query. */
  public static int calculateResultCount(
      final ISession session,
      final FeatureTypeInfo typeInfo,
      final Query query,
      final ArcSdeVersionHandler versioningHandler)
      throws IOException {

    ArcSDEQuery countQuery = null;
    final int count;
    try {
      final SimpleFeatureType fullSchema = typeInfo.getFeatureType();
      if (typeInfo.isInProcessView()) {
        final SeQueryInfo definitionQuery = typeInfo.getSdeDefinitionQuery();
        final PlainSelect viewSelectStatement = typeInfo.getDefinitionQuery();
        countQuery =
            createInprocessViewQuery(
                session, fullSchema, query, definitionQuery, viewSelectStatement);
      } else {
        final FIDReader fidStrategy = typeInfo.getFidStrategy();
        countQuery = createQuery(session, fullSchema, query, fidStrategy, versioningHandler);
      }
      count = countQuery.calculateResultCount();
    } finally {
      if (countQuery != null) {
        countQuery.close();
      }
    }
    return count;
  }
  /**
   * Fetches an SeRow of data.
   *
   * @throws IOException (DataSourceException) if the fetching fails
   * @throws IllegalStateException if the query was already closed or {@link #execute()} hastn't
   *     been called yet
   */
  public SdeRow fetch() throws IOException, IllegalStateException {
    if (this.query == null) {
      throw new IllegalStateException("query closed or not yet executed");
    }

    final SeQuery seQuery = getSeQuery();
    // commented out while SeToJTSGeometryFactory is in development
    // if (currentRow == null) {
    // GeometryFactory geomFac = new SeToJTSGeometryFactory();
    // currentRow = new SdeRow(geomFac);
    // int geometryIndex = -1;
    // for (int i = 0; i < schema.getAttributeCount(); i++) {
    // if (schema.getDescriptor(i) instanceof GeometryDescriptor) {
    // geometryIndex = i;
    // break;
    // }
    // }
    // currentRow.setGeometryIndex(geometryIndex);
    // }
    // currentRow = session.fetch(seQuery, currentRow);

    try {
      currentRow = session.fetch(seQuery);
    } catch (IOException e) {
      close();
      String msg = "Error fetching row for " + this.schema.getTypeName() + "[";
      msg += "\nFilter: " + filters.sourceFilter;
      msg += "\n where clause sent: " + filters.sdeSqlConstruct.getWhere();
      msg += "\ngeometry filter:" + filters.geometryFilter;
      LOGGER.log(Level.WARNING, msg, e);
      throw e;
    } catch (Exception e) {
      close();
      LOGGER.log(Level.SEVERE, "fetching row: " + e.getMessage(), e);
      throw new DataSourceException("fetching row: " + e.getMessage(), e);
    }

    if (currentRow != null) {
      currentRow.setPreviousValues(this.previousRowValues);
      previousRowValues = currentRow.getAll();
    }
    return currentRow;
  }
  /** Convenient method to just calculate the resulting bound box of a given query. */
  public static Envelope calculateQueryExtent(
      final ISession session,
      final FeatureTypeInfo typeInfo,
      final Query query,
      final ArcSdeVersionHandler versioningHandler)
      throws IOException {

    final SimpleFeatureType fullSchema = typeInfo.getFeatureType();
    final GeometryDescriptor geometryDescriptor = fullSchema.getGeometryDescriptor();
    if (geometryDescriptor == null) {
      return null;
    }
    final String defaultGeomAttName = geometryDescriptor.getLocalName();

    // we're calculating the bounds, so we'd better be sure and add the
    // spatial column to the query's propertynames
    final Query realQuery = new Query(query);
    realQuery.setPropertyNames(new String[] {defaultGeomAttName});

    final ArcSDEQuery boundsQuery;

    if (typeInfo.isInProcessView()) {
      final SeQueryInfo definitionQuery = typeInfo.getSdeDefinitionQuery();
      final PlainSelect viewSelectStatement = typeInfo.getDefinitionQuery();
      boundsQuery =
          createInprocessViewQuery(
              session, fullSchema, realQuery, definitionQuery, viewSelectStatement);
    } else {
      final FIDReader fidStrategy = typeInfo.getFidStrategy();
      boundsQuery = createQuery(session, fullSchema, realQuery, fidStrategy, versioningHandler);
    }

    Envelope queryExtent = null;
    try {
      Filter unsupportedFilter = boundsQuery.getFilters().getUnsupportedFilter();
      if (unsupportedFilter == Filter.INCLUDE) {
        // we can only use an optimized bounds calculation if the
        // query is fully supported by sde
        queryExtent = boundsQuery.calculateQueryExtent();
      }
    } finally {
      boundsQuery.close();
    }
    return queryExtent;
  }
 /**
  * Closes the query.
  *
  * <p>The {@link Session connection} used by the query is not closed by this operation as it was
  * provided by the calling code and thus it is its responsibility to handle the connection life
  * cycle.
  *
  * @throws IOException
  */
 public void close() throws IOException {
   close(this.query, session);
   this.query = null;
 }