Package org.jpox.store.rdbms.query

Source Code of org.jpox.store.rdbms.query.JDOQLQuery

/**********************************************************************
Copyright (c) 2003 Mike Martin (TJDO) and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:
2003 Erik Bengtson - removed unused import
2003 Andy Jefferson - commented and localised
2004 Andy Jefferson - converted to use Logger
2004 Andy Jefferson - added support for uniqueness of query
2004 Andy Jefferson - added Single-String query support
2005 Andy Jefferson - added timeout support
2005 Andy Jefferson - added implicit variable/parameter support
2008 Andy Jefferson - refactored compiler to be stand-alone. Major changes
    ...
**********************************************************************/
package org.jpox.store.rdbms.query;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import org.jpox.ObjectManager;
import org.jpox.exceptions.JPOXException;
import org.jpox.store.Extent;
import org.jpox.store.mapped.expression.QueryExpression;
import org.jpox.store.mapped.query.CollectionCandidates;
import org.jpox.store.mapped.query.Evaluator;
import org.jpox.store.mapped.query.Queryable;
import org.jpox.store.query.AbstractJDOQLQuery;
import org.jpox.store.query.JDOQLSingleStringParser;
import org.jpox.store.query.Query;
import org.jpox.store.query.QueryCompiler;
import org.jpox.store.query.QueryResult;
import org.jpox.store.query.ResultObjectFactory;
import org.jpox.store.rdbms.RDBMSManager;
import org.jpox.store.rdbms.adapter.RDBMSAdapter;
import org.jpox.util.JPOXLogger;

/**
* RDBMS representation of a JDOQL query for use by JPOX.
* The query can be specified via method calls, or via a single-string form.
*
* @see Query
* @version $Revision: 1.40 $
*/
public class JDOQLQuery extends AbstractJDOQLQuery
{
    /** The Query Statement. */
    protected transient QueryExpression queryStmt = null;

    /** Candidates for this query. */
    protected transient Queryable candidates = null;

    /**
     * Constructs a new query instance that uses the given persistence manager.
     * @param om the associated ObjectManager for this query.
     */
    public JDOQLQuery(ObjectManager om)
    {
        this(om, (JDOQLQuery)null);
    }

    /**
     * Constructs a new query instance having the same criteria as the given query.
     * @param om The ObjectManager
     * @param q The query from which to copy criteria.
     */
    public JDOQLQuery(ObjectManager om, JDOQLQuery q)
    {
        super(om);

        if (q == null)
        {
            candidateClass = null;
            candidateClassName = null;
            filter = null;
            imports = null;
            explicitVariables = null;
            explicitParameters = null;
            grouping = null;
            ordering = null;
            result = null;
            resultClass = null;
            resultClassName = null;
            range = null;
            fromInclNo = 0;
            toExclNo = Long.MAX_VALUE;
        }
        else
        {
            candidateClass = q.candidateClass;
            candidateClassName = q.candidateClassName;
            filter = q.filter;
            imports = q.imports;
            explicitVariables = q.explicitVariables;
            explicitParameters = q.explicitParameters;
            grouping = q.grouping;
            ordering = q.ordering;
            result = q.result;
            resultClass = q.resultClass;
            resultClassName = q.resultClassName;
            range = q.range;
            fromInclNo = q.fromInclNo;
            toExclNo = q.toExclNo;

            // JDO 1.0.1, Sect 12.6.3 : IgnoreCache is preserved when using other query baseline
            ignoreCache = q.ignoreCache;
        }
    }

    /**
     * Constructor for a JDOQL query where the query is specified using the "Single-String" format.
     * @param om The persistence manager
     * @param query The query string
     */
    public JDOQLQuery(ObjectManager om, String query)
    {
        super(om);

        // Parse the single-string query for errors
        new JDOQLSingleStringParser(this, query).parse();
    }

    /**
     * Accessor for the candidates for the query.
     * This is only valid after compiling the query.
     * @return Candidates for the query
     */
    public Queryable getCandidates()
    {
        return candidates;
    }

    /**
     * Equality operator for JDOQL.
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj)
    {
        if (obj == this)
        {
            return true;
        }
   
        if (!(obj instanceof JDOQLQuery) || !super.equals(obj))
        {
            return false;
        }
   
        return true;
    }

    /**
     * Method to compile the query.
     * @param forExecute Whether to compile ready for execution
     */
    protected void compileInternal(boolean forExecute, Map parameterValues)
    {
        if (isCompiled)
        {
            return;
        }

        try
        {
            if (forExecute)
            {
                // Compile for execution
                if (JPOXLogger.QUERY.isDebugEnabled())
                {
                    JPOXLogger.QUERY.debug(LOCALISER.msg("021044", "JDOQL", getSingleStringQuery(), "execution"));
                }

                // Compile the query for execution
                JDOQLQueryCompiler c = new JDOQLQueryCompiler(this, getParsedImports(), parameterValues);
                queryStmt = (QueryExpression)c.compile(QueryCompiler.COMPILE_EXECUTION);
                resultMetaData = c.getResultMetaData();
                candidateClass = c.getCandidateClass();
                candidates = c.getCandidates();
                distinct = c.getDistinct();
                resultClass = c.getResultClass();
                fromInclNo = c.getRangeFromIncl();
                toExclNo = c.getRangeToExcl();
                c.close();
                c = null;
            }
            else
            {
                // Use the compiler to perform a "pre-compile" check to validate the expressions
                if (JPOXLogger.QUERY.isDebugEnabled())
                {
                    JPOXLogger.QUERY.debug(LOCALISER.msg("021044", "JDOQL", getSingleStringQuery(), "precompile"));
                }

                // Compile the query syntactically
                JDOQLQueryCompiler c = new JDOQLQueryCompiler(this, getParsedImports(), null);
                c.compile(QueryCompiler.COMPILE_SYNTAX);
                resultMetaData = c.getResultMetaData();
                candidateClass = c.getCandidateClass();
                candidates = c.getCandidates();
                distinct = c.getDistinct();
                resultClass = c.getResultClass();
                fromInclNo = c.getRangeFromIncl();
                toExclNo = c.getRangeToExcl();
                c.close();
                c = null;
            }

            isCompiled = true;
        }
        catch (JPOXException jpe)
        {
            // Compile failed
            discardCompiled();
            isCompiled = false;
            throw jpe;
        }
    }

    /**
     * Method to discard our current compiled query due to changes.
     * @see org.jpox.store.query.Query#discardCompiled()
     */
    protected void discardCompiled()
    {
        super.discardCompiled();
        queryStmt = null;
    }

    /**
     * Convenience method to return whether the query should return a single row.
     * @return Whether a single row should result
     */
    protected boolean shouldReturnSingleRow()
    {
        if (unique)
        {
            // UNIQUE implies a single row
            return true;
        }
        else if (grouping != null)
        {
            // GROUP BY implies multiple possible
            return false;
        }
        else if (candidates instanceof ResultExpressionsQueryable)
        {
            // All result expressions being aggregate implies a single row
            return ((ResultExpressionsQueryable)candidates).hasAggregatedExpressionsOnly();
        }
        return false;
    }

    /**
     * Execute the query and return the filtered QueryResult.
     * @param parameters Map containing all of the parameters.
     * @return the filtered QueryResult.
     */
    protected Object performExecute(Map parameters)
    {
        // Throw away any existing compilation remnants
        discardCompiled();

        // Create a compiled query ready for execution
        try
        {
            // execution-compile the query statement
            long startTime = System.currentTimeMillis();
            compileInternal(true, parameters);
            if (JPOXLogger.QUERY.isDebugEnabled())
            {
                JPOXLogger.QUERY.debug(LOCALISER.msg("021045",
                    "JDOQL", "" + (System.currentTimeMillis() - startTime)));
            }
        }
        finally
        {
            if (!isCompiled)
            {
                discardCompiled();
            }
        }

        if (candidates.isEmpty())
        {
            // if the candidates are empty, we don't have to go to the database
            // to find out that we have no elements to return
            return new ArrayList();
        }

        // Apply the Query FetchPlan to the query
        // Note : we could have added getFetchPlan() to Queryable, but this would affect *many* classes
        // so leaving like this for now
        if (candidates instanceof CollectionCandidates)
        {
            ((CollectionCandidates)candidates).getFetchPlan().setGroups(getFetchPlan().getGroups());
        }
        else if (candidates instanceof Extent)
        {
            ((Extent)candidates).getFetchPlan().setGroups(getFetchPlan().getGroups());
        }

        boolean useFetchPlan = om.getOMFContext().getPersistenceConfiguration().getBooleanProperty("org.jpox.query.useFetchPlan");
        if (extensions != null && extensions.containsKey("org.jpox.query.useFetchPlan"))
        {
            useFetchPlan = Boolean.valueOf((String)extensions.get("org.jpox.query.useFetchPlan")).booleanValue();
        }

        // Create a processor for extracting the objects from the ResultSet
        rof = candidates.newResultObjectFactory(queryStmt, getIgnoreCache(), resultClass, useFetchPlan);
        if (rof instanceof PersistentIDROF)
        {
            // Allow for the user specifying an Extent of a base class but restricting this query to a subclass
            ((PersistentIDROF)rof).setPersistentClass(candidateClass);
        }

        // Make sure the datastore is prepared for the query
        prepareDatastore();

        // Execute the query
        if (JPOXLogger.QUERY.isDebugEnabled())
        {
            JPOXLogger.QUERY.debug(LOCALISER.msg("021046", "JDOQL", getSingleStringQuery()));
        }
        Evaluator eval = getEvaluator(om, distinct, this, rof, candidateCollection);
        QueryResult qr = (QueryResult)eval.evaluate(queryStmt);
        queryResults.add(qr);

        return qr;
    }

    /**
     * Method to return the evaluator to use for this JDOQL query.
     * @param query The query
     * @param distinct whether to return distinct results
     * @param rof ResultObjectFactory
     * @param candidateCollection Any candidate collection
     * @return The evaluator
     */
    protected Evaluator getEvaluator(ObjectManager om, boolean distinct, Query query,
            ResultObjectFactory rof, Collection candidateCollection)
    {
        return new SQLEvaluator(this, distinct, rof, candidateCollection);
    }

    /**
     * Method to return if the query results should have the range checked and unnecessary rows
     * discarded. This is for where the query language has specified a range but the datastore doesnt
     * allow removal of unnecessary results in the query itself (so has to be done in post-processing).
     * This implementation returns false and so should be overridden by query languages to match their
     * capabilities.
     * @return Whether to apply range checks in post-processing of results.
     */
    protected boolean applyRangeChecks()
    {
        // Gather information about whether we should apply range limits in this post-processing step
        boolean range_specified = (fromInclNo >= 0 && toExclNo >= 0 && (fromInclNo != 0 || toExclNo != Long.MAX_VALUE));
        if (!range_specified)
        {
            // No range specified so dont apply checks!
            return false;
        }

        RDBMSManager storeMgr = (RDBMSManager)om.getStoreManager();
        RDBMSAdapter dba = (RDBMSAdapter)storeMgr.getDatastoreAdapter();
        boolean using_limit_select_clause = (dba.getRangeByLimitSelectClause(fromInclNo, toExclNo).length() > 0);
        boolean using_limit_where_clause = (dba.getRangeByLimitWhereClause(fromInclNo, toExclNo).length() > 0);
        boolean using_rownum = (dba.getRangeByRowNumberColumn().length() > 0);
        boolean applyRangeChecks =
            (range_specified && !using_limit_select_clause && !using_limit_where_clause && !using_rownum);

        return applyRangeChecks;
    }
}
TOP

Related Classes of org.jpox.store.rdbms.query.JDOQLQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.