/** * Method to create a PreparedStatement for use with the query. * * @param conn the Connection * @param queryStmt The statement text for the query * @param query The query * @return the PreparedStatement * @throws SQLException Thrown if an error occurs creating the statement */ public static PreparedStatement getPreparedStatementForQuery( ManagedConnection conn, String queryStmt, Query query) throws SQLException { // Apply any non-standard result set definition if required (either from the PMF, or via query // extensions) String rsTypeString = RDBMSQueryUtils.getResultSetTypeForQuery(query); if (rsTypeString != null && (!rsTypeString.equals("scroll-sensitive") && !rsTypeString.equals("forward-only") && !rsTypeString.equals("scroll-insensitive"))) { throw new NucleusUserException(LOCALISER.msg("052510")); } if (rsTypeString != null) { DatastoreAdapter dba = ((RDBMSStoreManager) query.getStoreManager()).getDatastoreAdapter(); // Add checks on what the DatastoreAdapter supports if (rsTypeString.equals("scroll-sensitive") && !dba.supportsOption(DatastoreAdapter.RESULTSET_TYPE_SCROLL_SENSITIVE)) { NucleusLogger.DATASTORE_RETRIEVE.info( "Query requested to run with result-set type of " + rsTypeString + " yet not supported by adapter. Using forward-only"); rsTypeString = "forward-only"; } else if (rsTypeString.equals("scroll-insensitive") && !dba.supportsOption(DatastoreAdapter.RESULTSET_TYPE_SCROLL_INSENSITIVE)) { NucleusLogger.DATASTORE_RETRIEVE.info( "Query requested to run with result-set type of " + rsTypeString + " yet not supported by adapter. Using forward-only"); rsTypeString = "forward-only"; } else if (rsTypeString.equals("forward-only") && !dba.supportsOption(DatastoreAdapter.RESULTSET_TYPE_FORWARD_ONLY)) { NucleusLogger.DATASTORE_RETRIEVE.info( "Query requested to run with result-set type of " + rsTypeString + " yet not supported by adapter. Using scroll-sensitive"); rsTypeString = "scroll-sensitive"; } } String rsConcurrencyString = RDBMSQueryUtils.getResultSetConcurrencyForQuery(query); if (rsConcurrencyString != null && (!rsConcurrencyString.equals("read-only") && !rsConcurrencyString.equals("updateable"))) { throw new NucleusUserException(LOCALISER.msg("052511")); } SQLController sqlControl = ((RDBMSStoreManager) query.getStoreManager()).getSQLController(); PreparedStatement ps = sqlControl.getStatementForQuery(conn, queryStmt, rsTypeString, rsConcurrencyString); return ps; }
/** * Accessor for the result set type for the specified query. Uses the persistence property * "datanucleus.rdbms.query.resultSetType" and allows it to be overridden by the query extension * of the same name. Checks both the PMF, and also the query extensions. * * @param query The query * @return The result set type string */ public static String getResultSetTypeForQuery(Query query) { String rsTypeString = query .getExecutionContext() .getNucleusContext() .getPersistenceConfiguration() .getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_RESULT_SET_TYPE); Object rsTypeExt = query.getExtension(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_RESULT_SET_TYPE); if (rsTypeExt != null) { rsTypeString = (String) rsTypeExt; } return rsTypeString; }
/** * Convenience method to return if the specified query should use an "UPDATE" lock on returned * objects. First checks whether serializeRead is set on the query and, if not, falls back to the * setting for the class. * * @param query The query * @return Whether to use an "UPDATE" lock */ public static boolean useUpdateLockForQuery(Query query) { if (query.getSerializeRead() != null) { if (!query.getExecutionContext().getTransaction().isActive()) { // Only applies in a transaction return false; } // Query value takes top priority return query.getSerializeRead(); } else { // Fallback to transaction or class itself return query.getExecutionContext().getSerializeReadForClass(query.getCandidateClassName()); } }
/** * Method to apply any restrictions to the created ResultSet. * * @param ps The PreparedStatement * @param query The query * @param applyTimeout Whether to apply the query timeout (if any) direct to the PreparedStatement * @throws SQLException Thrown when an error occurs applying the constraints */ public static void prepareStatementForExecution( PreparedStatement ps, Query query, boolean applyTimeout) throws SQLException { NucleusContext nucleusCtx = query.getExecutionContext().getNucleusContext(); RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager(); PersistenceConfiguration conf = nucleusCtx.getPersistenceConfiguration(); if (applyTimeout) { Integer timeout = query.getDatastoreReadTimeoutMillis(); if (timeout != null && timeout > 0) { ps.setQueryTimeout(timeout / 1000); } } // Apply any fetch size int fetchSize = 0; if (query.getFetchPlan().getFetchSize() > 0) { // FetchPlan has a size set so use that fetchSize = query.getFetchPlan().getFetchSize(); } if (storeMgr.getDatastoreAdapter().supportsQueryFetchSize(fetchSize)) { ps.setFetchSize(fetchSize); } // Apply any fetch direction String fetchDir = conf.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_FETCH_DIRECTION); Object fetchDirExt = query.getExtension(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_FETCH_DIRECTION); if (fetchDirExt != null) { fetchDir = (String) fetchDirExt; if (!fetchDir.equals("forward") && !fetchDir.equals("reverse") && !fetchDir.equals("unknown")) { throw new NucleusUserException(LOCALISER.msg("052512")); } } if (fetchDir.equals("reverse")) { ps.setFetchDirection(ResultSet.FETCH_REVERSE); } else if (fetchDir.equals("unknown")) { ps.setFetchDirection(ResultSet.FETCH_UNKNOWN); } // Add a limit on the number of rows to include the maximum we may need long toExclNo = query.getRangeToExcl(); if (toExclNo != 0 && toExclNo != Long.MAX_VALUE) { if (toExclNo > Integer.MAX_VALUE) { // setMaxRows takes an int as input so limit to the correct range ps.setMaxRows(Integer.MAX_VALUE); } else { ps.setMaxRows((int) toExclNo); } } }