/** Find and return a single bean using its unique id. */ public <T> T find(OrmQueryRequest<T> request) { T bean = null; CQuery<T> cquery = queryBuilder.buildQuery(request); try { cquery.prepareBindExecuteQuery(); if (request.isLogSql()) { logSql(cquery); } if (cquery.readBean()) { bean = cquery.getLoadedBean(); } if (request.isLogSummary()) { logFindBeanSummary(cquery); } request.executeSecondaryQueries(defaultSecondaryQueryBatchSize); return bean; } catch (SQLException e) { throw cquery.createPersistenceException(e); } finally { cquery.close(); } }
/** * Read many beans using an iterator (except you need to close() the iterator when you have * finished). */ public <T> QueryIterator<T> findIterate(OrmQueryRequest<T> request) { CQuery<T> cquery = queryBuilder.buildQuery(request); request.setCancelableQuery(cquery); try { if (!cquery.prepareBindExecuteQuery()) { // query has been cancelled already logger.trace("Future fetch already cancelled"); return null; } if (request.isLogSql()) { logSql(cquery); } int iterateBufferSize = request.getSecondaryQueriesMinBatchSize(defaultSecondaryQueryBatchSize); QueryIterator<T> readIterate = cquery.readIterate(iterateBufferSize, request); if (request.isLogSummary()) { logFindManySummary(cquery); } return readIterate; } catch (SQLException e) { throw cquery.createPersistenceException(e); } }
/** 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; }
public CQueryPredicates(Binder binder, OrmQueryRequest<?> request) { this.binder = binder; this.request = request; this.query = request.getQuery(); this.bindParams = query.getBindParams(); this.idValue = query.getId(); }
/** Convert named parameters into an OrderedList. */ private void buildBindWhereRawSql(boolean buildSql, boolean parseRaw, DeployParser parser) { if (buildSql || bindParams != null) { whereRawSql = buildWhereRawSql(); boolean hasRaw = !"".equals(whereRawSql); if (hasRaw && parseRaw) { // parse with encrypted property awareness. This means that if we have // an encrypted property we will insert special named parameter place // holders for binding the encryption key values parser.setEncrypted(true); whereRawSql = parser.parse(whereRawSql); parser.setEncrypted(false); } if (bindParams != null) { if (hasRaw) { whereRawSql = BindParamsParser.parse(bindParams, whereRawSql, request.getBeanDescriptor()); } else if (query.isRawSql() && !buildSql) { // RawSql query hit cached query plan. Need to convert // named parameters into positioned parameters so that // the named parameters are bound RawSql.Sql sql = query.getRawSql().getSql(); String s = sql.isParsed() ? sql.getPreWhere() : sql.getUnparsedSql(); if (bindParams.requiresNamedParamsPrepare()) { BindParamsParser.parse(bindParams, s); } } } } }
public String bind(DataBind dataBind) throws SQLException { StringBuilder bindLog = new StringBuilder(); if (idValue != null) { // this is a find by id type query... request.getBeanDescriptor().bindId(dataBind, idValue); bindLog.append(idValue); } if (bindParams != null) { // bind named and positioned parameters... binder.bind(bindParams, dataBind, bindLog); } if (whereExprBindValues != null) { for (int i = 0; i < whereExprBindValues.size(); i++) { Object bindValue = whereExprBindValues.get(i); binder.bindObject(dataBind, bindValue); if (i > 0 || idValue != null) { bindLog.append(","); } bindLog.append(bindValue); } } if (filterManyExprBindValues != null) { for (int i = 0; i < filterManyExprBindValues.size(); i++) { Object bindValue = filterManyExprBindValues.get(i); binder.bindObject(dataBind, bindValue); if (i > 0 || idValue != null) { bindLog.append(","); } bindLog.append(bindValue); } } if (havingNamedParams != null) { // bind named parameters in having... bindLog.append(" havingNamed "); binder.bind(havingNamedParams.list(), dataBind, bindLog); } if (havingExprBindValues != null) { // bind having expression... bindLog.append(" having "); for (int i = 0; i < havingExprBindValues.size(); i++) { Object bindValue = havingExprBindValues.get(i); binder.bindObject(dataBind, bindValue); if (i > 0) { bindLog.append(","); } bindLog.append(bindValue); } } return bindLog.toString(); }
/** Build and execute the row count query. */ public <T> int findRowCount(OrmQueryRequest<T> request) { CQueryRowCount rcQuery = queryBuilder.buildRowCountQuery(request); try { int rowCount = rcQuery.findRowCount(); if (request.isLogSql()) { String logSql = rcQuery.getGeneratedSql(); if (TransactionManager.SQL_LOGGER.isTraceEnabled()) { logSql += "; --bind(" + rcQuery.getBindLog() + ")"; } request.logSql(logSql); } if (request.isLogSummary()) { request.getTransaction().logSummary(rcQuery.getSummary()); } if (request.getQuery().isFutureFetch()) { logger.debug("Future findRowCount completed!"); request.getTransaction().end(); } return rowCount; } catch (SQLException e) { throw CQuery.createPersistenceException( e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql()); } }
/** Build and execute the find Id's query. */ public <T> BeanIdList findIds(OrmQueryRequest<T> request) { CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request); try { BeanIdList list = rcQuery.findIds(); if (request.isLogSql()) { String logSql = rcQuery.getGeneratedSql(); if (TransactionManager.SQL_LOGGER.isTraceEnabled()) { logSql += "; --bind(" + rcQuery.getBindLog() + ")"; } request.logSql(logSql); } if (request.isLogSummary()) { request.getTransaction().logSummary(rcQuery.getSummary()); } if (!list.isFetchingInBackground() && request.getQuery().isFutureFetch()) { // end the transaction for futureFindIds (it had it's own one) logger.debug("Future findIds completed!"); request.getTransaction().end(); } return list; } catch (SQLException e) { throw CQuery.createPersistenceException( e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql()); } }
/** Parse/Convert property names to database columns in the where and order by clauses etc. */ private void parsePropertiesToDbColumns(DeployParser deployParser) { // order by is dependent on the manyProperty (if there is one) String logicalOrderBy = deriveOrderByWithMany(request.getManyProperty()); if (logicalOrderBy != null) { dbOrderBy = deployParser.parse(logicalOrderBy); } // create a copy of the includes required to support the orderBy orderByIncludes = new HashSet<String>(deployParser.getIncludes()); dbWhere = deriveWhere(deployParser); dbFilterMany = deriveFilterMany(deployParser); dbHaving = deriveHaving(deployParser); // all includes including ones for manyWhere clause predicateIncludes = deployParser.getIncludes(); }
/** This combines the sql from named/positioned parameters and expressions. */ private void prepare(boolean buildSql, boolean parseRaw, DeployParser deployParser) { buildBindWhereRawSql(buildSql, parseRaw, deployParser); buildBindHavingRawSql(buildSql, parseRaw, deployParser); SpiExpressionList<?> whereExp = query.getWhereExpressions(); if (whereExp != null) { DefaultExpressionRequest whereReq = new DefaultExpressionRequest(request, deployParser); whereExprBindValues = whereExp.buildBindValues(whereReq); if (buildSql) { whereExprSql = whereExp.buildSql(whereReq); } } BeanPropertyAssocMany<?> manyProperty = request.getManyProperty(); if (manyProperty != null) { OrmQueryProperties chunk = query.getDetail().getChunk(manyProperty.getName(), false); SpiExpressionList<?> filterMany = chunk.getFilterMany(); if (filterMany != null) { DefaultExpressionRequest filterReq = new DefaultExpressionRequest(request, deployParser); filterManyExprBindValues = filterMany.buildBindValues(filterReq); if (buildSql) { filterManyExprSql = filterMany.buildSql(filterReq); } } } // having expression SpiExpressionList<?> havingExpr = query.getHavingExpressions(); if (havingExpr != null) { DefaultExpressionRequest havingReq = new DefaultExpressionRequest(request, deployParser); havingExprBindValues = havingExpr.buildBindValues(havingReq); if (buildSql) { havingExprSql = havingExpr.buildSql(havingReq); } } if (buildSql) { parsePropertiesToDbColumns(deployParser); } }
/** There is a many property so we need to make sure the ordering is appropriate. */ private String deriveOrderByWithMany(BeanPropertyAssocMany<?> manyProp) { if (manyProp == null) { return parseOrderBy(); } String orderBy = parseOrderBy(); BeanDescriptor<?> desc = request.getBeanDescriptor(); String orderById = desc.getDefaultOrderBy(); if (orderBy == null) { orderBy = orderById; } // check for default ordering on the many property... String manyOrderBy = manyProp.getFetchOrderBy(); if (manyOrderBy != null) { orderBy = orderBy + ", " + CQueryBuilder.prefixOrderByFields(manyProp.getName(), manyOrderBy); } if (request.isFindById()) { // only one master bean so should be fine... return orderBy; } if (orderBy.startsWith(orderById)) { return orderBy; } // more than one top level row may be returned so // we need to make sure their is an order by on the // top level first (to ensure master/detail construction). int manyPos = orderBy.indexOf(manyProp.getName()); int idPos = orderBy.indexOf(" " + orderById); if (manyPos == -1) { // no ordering of the many if (idPos == -1) { // append the orderById so that master level objects are ordered // even if the orderBy is not unique for the master object return orderBy + ", " + orderById; } // orderById is already in the order by clause return orderBy; } if (idPos <= -1 || idPos >= manyPos) { if (idPos > manyPos) { // there was an error with the order by... String msg = "A Query on [" + desc + "] includes a join to a 'many' association [" + manyProp.getName(); msg += "] with an incorrect orderBy [" + orderBy + "]. The id property [" + orderById + "]"; msg += " must come before the many property [" + manyProp.getName() + "] in the orderBy."; msg += " Ebean has automatically modified the orderBy clause to do this."; logger.warn(msg); } // the id needs to come before the manyPropName orderBy = orderBy.substring(0, manyPos) + orderById + ", " + orderBy.substring(manyPos); } return orderBy; }
private String parseOrderBy() { return CQueryOrderBy.parse(request.getBeanDescriptor(), query); }
public void prepare(boolean buildSql) { DeployParser deployParser = request.createDeployParser(); prepare(buildSql, true, deployParser); }
public String bind(DataBind dataBind) throws SQLException { StringBuilder bindLog = new StringBuilder(); if (query.isVersionsBetween() && binder.isBindAsOfWithFromClause()) { // sql2011 based versions between timestamp syntax Timestamp start = query.getVersionStart(); Timestamp end = query.getVersionEnd(); bindLog.append("between ").append(start).append(" and ").append(end); binder.bindObject(dataBind, start); binder.bindObject(dataBind, end); bindLog.append(", "); } List<String> historyTableAlias = query.getAsOfTableAlias(); if (historyTableAlias != null && binder.isBindAsOfWithFromClause()) { // bind the asOf value for each table alias as part of the from/join clauses // there is one effective date predicate per table alias Timestamp asOf = query.getAsOf(); bindLog.append("asOf ").append(asOf); for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) { binder.bindObject(dataBind, asOf); } bindLog.append(", "); } if (idValue != null) { // this is a find by id type query... request.getBeanDescriptor().bindId(dataBind, idValue); bindLog.append(idValue); } if (bindParams != null) { // bind named and positioned parameters... binder.bind(bindParams, dataBind, bindLog); } if (whereExprBindValues != null) { for (int i = 0; i < whereExprBindValues.size(); i++) { Object bindValue = whereExprBindValues.get(i); bindValue = binder.bindObject(dataBind, bindValue); if (i > 0 || idValue != null) { bindLog.append(","); } bindLog.append(bindValue); } } if (filterManyExprBindValues != null) { for (int i = 0; i < filterManyExprBindValues.size(); i++) { Object bindValue = filterManyExprBindValues.get(i); bindValue = binder.bindObject(dataBind, bindValue); if (i > 0 || idValue != null) { bindLog.append(","); } bindLog.append(bindValue); } } if (historyTableAlias != null && !binder.isBindAsOfWithFromClause()) { // bind the asOf value for each table alias after all the normal predicates // there is one effective date predicate per table alias Timestamp asOf = query.getAsOf(); bindLog.append(" asOf ").append(asOf); for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) { binder.bindObject(dataBind, asOf); } } if (havingNamedParams != null) { // bind named parameters in having... bindLog.append(" havingNamed "); binder.bind(havingNamedParams.list(), dataBind, bindLog); } if (havingExprBindValues != null) { // bind having expression... bindLog.append(" having "); for (int i = 0; i < havingExprBindValues.size(); i++) { Object bindValue = havingExprBindValues.get(i); bindValue = binder.bindObject(dataBind, bindValue); if (i > 0) { bindLog.append(","); } bindLog.append(bindValue); } } return bindLog.toString(); }
/** 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<Object> idList = query.getIdList(); if (idList == null) { // running in foreground thread (not FutureIds query) idList = Collections.synchronizedList(new ArrayList<Object>()); 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(new DataBind(pstmt)); ResultSet rset = pstmt.executeQuery(); dataReader = new RsetDataReader(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(); } }
/** Find a list/map/set of beans. */ public <T> BeanCollection<T> findMany(OrmQueryRequest<T> request) { // flag indicating whether we need to close the resources... boolean useBackgroundToContinueFetch = false; CQuery<T> cquery = queryBuilder.buildQuery(request); request.setCancelableQuery(cquery); try { if (!cquery.prepareBindExecuteQuery()) { // query has been cancelled already logger.trace("Future fetch already cancelled"); return null; } if (request.isLogSql()) { logSql(cquery); } BeanCollection<T> beanCollection = cquery.readCollection(); BeanCollectionTouched collectionTouched = request.getQuery().getBeanCollectionTouched(); if (collectionTouched != null) { // register a listener that wants to be notified when the // bean collection is first used beanCollection.setBeanCollectionTouched(collectionTouched); } if (cquery.useBackgroundToContinueFetch()) { // stop the request from putting connection back into pool // before background fetching is finished. request.setBackgroundFetching(); useBackgroundToContinueFetch = true; BackgroundFetch fetch = new BackgroundFetch(cquery); FutureTask<Integer> future = new FutureTask<Integer>(fetch); beanCollection.setBackgroundFetch(future); backgroundExecutor.execute(future); } if (request.isLogSummary()) { logFindManySummary(cquery); } request.executeSecondaryQueries(defaultSecondaryQueryBatchSize); return beanCollection; } catch (SQLException e) { throw cquery.createPersistenceException(e); } finally { if (useBackgroundToContinueFetch) { // left closing resources to BackgroundFetch... } else { if (cquery != null) { cquery.close(); } if (request.getQuery().isFutureFetch()) { // end the transaction for futureFindIds // as it had it's own transaction logger.debug("Future fetch completed!"); request.getTransaction().end(); } } } }