All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avaje.ebeaninternal.server.query.CQueryFetchIds Maven / Gradle / Ivy

There is a newer version: 8.1.1
Show newest version
package com.avaje.ebeaninternal.server.query;

import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.BeanIdList;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
import com.avaje.ebeaninternal.api.SpiTransaction;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
import com.avaje.ebeaninternal.server.type.DataReader;
import com.avaje.ebeaninternal.server.type.RsetDataReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Executes the select row count query.
 */
public class CQueryFetchIds {

  private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.class);

  /**
   * The overall find request wrapper object.
   */
  private final OrmQueryRequest request;

  private final BeanDescriptor desc;

  private final SpiQuery query;

  /**
   * Where clause predicates.
   */
  private final CQueryPredicates predicates;

  /**
   * The final sql that is generated.
   */
  private final String sql;

  private RsetDataReader dataReader;

  /**
   * The statement used to create the resultSet.
   */
  private PreparedStatement pstmt;

  private String bindLog;

  private int executionTimeMicros;

  private int rowCount;

  private final int maxRows;

  /**
   * Create the Sql select based on the request.
   */
  public CQueryFetchIds(OrmQueryRequest request, CQueryPredicates predicates, String sql) {

    this.request = request;
    this.query = request.getQuery();
    this.sql = sql;
    this.maxRows = query.getMaxRows();

    query.setGeneratedSql(sql);

    this.desc = request.getBeanDescriptor();
    this.predicates = predicates;
  }

  /**
   * Return a summary description of this query.
   */
  public String getSummary() {
    StringBuilder sb = new StringBuilder(80);
    sb.append("FindIds exeMicros[").append(executionTimeMicros)
        .append("] rows[").append(rowCount)
        .append("] type[").append(desc.getName())
        .append("] predicates[").append(predicates.getLogWhereSql())
        .append("] bind[").append(bindLog).append("]");

    return sb.toString();
  }

  /**
   * Return the bind log.
   */
  public String getBindLog() {
    return bindLog;
  }

  /**
   * Return the generated sql.
   */
  public String getGeneratedSql() {
    return sql;
  }

  /**
   * Execute the query returning the row count.
   */
  public BeanIdList findIds() throws SQLException {

    long startNano = System.nanoTime();

    try {
      // get the list that we are going to put the id's into.
      // This was already set so that it is available to be
      // read by other threads (it is a synchronised list)
      List idList = query.getIdList();
      if (idList == null) {
        // running in foreground thread (not FutureIds query)
        idList = Collections.synchronizedList(new ArrayList());
        query.setIdList(idList);
      }

      BeanIdList result = new BeanIdList(idList);

      SpiTransaction t = request.getTransaction();
      Connection conn = t.getInternalConnection();
      pstmt = conn.prepareStatement(sql);

      if (query.getBufferFetchSizeHint() > 0) {
        pstmt.setFetchSize(query.getBufferFetchSizeHint());
      }

      if (query.getTimeout() > 0) {
        pstmt.setQueryTimeout(query.getTimeout());
      }

      bindLog = predicates.bind(pstmt, conn);

      ResultSet rset = pstmt.executeQuery();
      dataReader = new RsetDataReader(request.getDataTimeZone(), rset);

      boolean hitMaxRows = false;
      boolean hasMoreRows = false;
      rowCount = 0;

      DbReadContext ctx = new DbContext();

      while (rset.next()) {
        Object idValue = desc.getIdBinder().read(ctx);
        idList.add(idValue);
        // reset back to 0
        dataReader.resetColumnPosition();
        rowCount++;

        if (maxRows > 0 && rowCount == maxRows) {
          hitMaxRows = true;
          hasMoreRows = rset.next();
          break;

        }
      }

      if (hitMaxRows) {
        result.setHasMore(hasMoreRows);
      }

      long exeNano = System.nanoTime() - startNano;
      executionTimeMicros = (int) exeNano / 1000;

      return result;

    } finally {
      close();
    }
  }

  /**
   * Close the resources.
   * 

* The jdbc resultSet and statement need to be closed. Its important that * this method is called. *

*/ private void close() { try { if (dataReader != null) { dataReader.close(); dataReader = null; } } catch (SQLException e) { logger.error("Error closing DataReader", e); } try { if (pstmt != null) { pstmt.close(); pstmt = null; } } catch (SQLException e) { logger.error("Error closing PreparedStatement", e); } } class DbContext implements DbReadContext { public void propagateState(Object e) { throw new RuntimeException("Not Called"); } public Mode getQueryMode() { return Mode.NORMAL; } public DataReader getDataReader() { return dataReader; } public Boolean isReadOnly() { return Boolean.FALSE; } @Override public boolean isDisableLazyLoading() { return false; } public boolean isRawSql() { return false; } public void register(String path, EntityBeanIntercept ebi) { } public void register(String path, BeanCollection bc) { } public BeanPropertyAssocMany getManyProperty() { // always null return null; } public PersistenceContext getPersistenceContext() { // always null return null; } public boolean isAutoTuneProfiling() { return false; } public void profileBean(EntityBeanIntercept ebi, String prefix) { // no-op } public void setCurrentPrefix(String currentPrefix, Map pathMap) { // no-op } public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) { // no-op } @Override public boolean isDraftQuery() { return false; } } }