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

org.datanucleus.query.evaluator.JavaQueryEvaluator Maven / Gradle / Ivy

Go to download

DataNucleus Core provides the primary components of a heterogenous Java persistence solution. It supports persistence API's being layered on top of the core functionality.

There is a newer version: 6.0.7
Show newest version
/**********************************************************************
Copyright (c) 2008 Erik Bengtson 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:
2008 Andy Jefferson - restructured to take in applyXXX flags and evaluate different parts if required
    ...
**********************************************************************/
package org.datanucleus.query.evaluator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.query.QueryUtils;
import org.datanucleus.query.compiler.QueryCompilation;
import org.datanucleus.query.expression.CreatorExpression;
import org.datanucleus.query.expression.Expression;
import org.datanucleus.query.expression.InvokeExpression;
import org.datanucleus.query.inmemory.InMemoryExpressionEvaluator;
import org.datanucleus.query.inmemory.InMemoryFailure;
import org.datanucleus.query.inmemory.VariableNotSetException;
import org.datanucleus.store.query.Query;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;

/**
 * Class to evaluate a Java "string-based" query in whole or part.
 * Takes in a list of instances and applies the required restrictions to the input giving a final result.
 * Typically extended for JDOQL, JPQL, SQL specifics.
 */
public abstract class JavaQueryEvaluator
{
    /** Name under which any set of results are stored in the state map. Used for aggregation. */
    public static final String RESULTS_SET = "DATANUCLEUS_RESULTS_SET";

    protected final String language;

    protected String candidateAlias = "this";

    /** Candidates objects to evaluate. */
    protected Collection candidates;

    /** Underlying "string-based" query. */
    protected Query query;

    /** Compilation of the underlying query, that we are evaluating. */
    protected QueryCompilation compilation;

    /** Map of input parameter values, keyed by the parameter name. */
    protected Map parameterValues;

    /** The evaluator. */
    protected InMemoryExpressionEvaluator evaluator;

    /** Map of state symbols for the query evaluation. */
    protected Map state;

    protected ClassLoaderResolver clr;

    /**
     * Constructor for the evaluator of a query in the specified language.
     * @param language Name of the language
     * @param query The underlying query
     * @param compilation Query compilation
     * @param parameterValues Input parameter values
     * @param clr ClassLoader resolver
     * @param candidates Candidate objects
     */
    public JavaQueryEvaluator(String language, Query query, QueryCompilation compilation, 
            Map parameterValues, ClassLoaderResolver clr, Collection candidates)
    {
        this.language = language;
        this.query = query;
        this.compilation = compilation;
        this.parameterValues = parameterValues;
        this.clr = clr;
        this.candidates = candidates;
        this.candidateAlias = (compilation.getCandidateAlias() != null ? 
                compilation.getCandidateAlias() : this.candidateAlias);

        state = new HashMap();
        state.put(this.candidateAlias, query.getCandidateClass());

        evaluator = new InMemoryExpressionEvaluator(query.getExecutionContext(),
            parameterValues, state, query.getParsedImports(), clr, this.candidateAlias, query.getLanguage());
    }

    /**
     * Method to evaluate a subquery of the query being evaluated.
     * @param subquery The subquery
     * @param compilation The subquery compilation
     * @param candidates The candidates for the subquery
     * @param outerCandidate The current outer candidate (for use when linking back to outer query)
     * @return The result
     */
    protected abstract Collection evaluateSubquery(Query subquery, QueryCompilation compilation, Collection candidates,
            Object outerCandidate);

    /**
     * Method to perform the evaluation, applying the query restrictions that are required.
     * @param applyFilter Whether to apply any filter constraints on the results
     * @param applyOrdering Whether to apply any order constraints on the results
     * @param applyResult Whether to apply any result/grouping/having on the results
     * @param applyResultClass Whether to apply any resultClass constraint on the results
     * @param applyRange Whether to apply any range constraint on the results
     * @return The results after evaluation.
     */
    public Collection execute(boolean applyFilter, boolean applyOrdering, boolean applyResult,
            boolean applyResultClass, boolean applyRange)
    {
        if (!applyFilter && !applyOrdering && !applyResult && !applyResultClass && !applyRange)
        {
            // Nothing to evaluate in-memory
            return candidates;
        }

        Collection executeCandidates = new ArrayList();
        Expression[] result = compilation.getExprResult();
        if (candidates != null)
        {
            if (applyResult && result != null && result.length > 1)
            {
                // Have result but not returning rows of candidate type so remove dupd candidates
                Iterator candIter = candidates.iterator();
                while (candIter.hasNext())
                {
                    Object candidate = candIter.next();
                    if (!executeCandidates.contains(candidate))
                    {
                        executeCandidates.add(candidate);
                    }
                }
            }
            else
            {
                executeCandidates.addAll(candidates);
            }
        }

        // TODO Where the subquery makes use of the parent query candidate, set the candidates for the
        // subquery using that. This currently just passes the same parent candidates in!
        String[] subqueryAliases = compilation.getSubqueryAliases();
        if (subqueryAliases != null)
        {
            for (int i=0;i 0)
            {
                if (c.compare(resultSet.get(i-1),resultSet.get(i)) != 0)
                {
                    group = new ArrayList();
                    groups.add(group);
                }
            }
            group.add(resultSet.get(i));
        }
        List result = new ArrayList();
        Expression having = compilation.getExprHaving();
        if (having != null)
        {
            for (int i=0; i 0)
            {
                groups.add(group);
            }
            for (int i = 0; i < resultSet.size(); i++)
            {
                if (i > 0)
                {
                    if (c.compare(resultSet.get(i - 1), resultSet.get(i)) != 0)
                    {
                        group = new ArrayList();
                        groups.add(group);
                    }
                }
                group.add(resultSet.get(i));
            }

            // Apply the result to the generated groups
            for (int i = 0; i < groups.size(); i++)
            {
                group = (List)groups.get(i);
                result.add(result(group));
            }
        }
        else
        {
            boolean aggregates = false;
            Expression[] resultExprs = compilation.getExprResult();
            if (resultExprs.length > 0 && resultExprs[0] instanceof CreatorExpression)
            {
                Expression[] resExpr = ((CreatorExpression)resultExprs[0]).getArguments().toArray(
                    new Expression[((CreatorExpression)resultExprs[0]).getArguments().size()]);
                for (int i = 0; i < resExpr.length; i++)
                {
                    if (resExpr[i] instanceof InvokeExpression)
                    {
                        String method = ((InvokeExpression) resExpr[i]).getOperation().toLowerCase();
                        if (method.equals("count") || method.equals("sum") || method.equals("avg") || 
                            method.equals("min") || method.equals("max"))
                        {
                            aggregates = true;
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < resultExprs.length; i++)
                {
                    if (resultExprs[i] instanceof InvokeExpression)
                    {
                        String method = ((InvokeExpression)resultExprs[i]).getOperation().toLowerCase();
                        if (method.equals("count") || method.equals("sum") || method.equals("avg") || 
                            method.equals("min") || method.equals("max"))
                        {
                            aggregates = true;
                        }
                    }
                }
            }
    
            if (aggregates)
            {
                result.add(result(resultSet));
            }
            else
            {
                for (int i = 0; i < resultSet.size(); i++)
                {
                    result.add(result(resultSet.get(i)));
                }
            }
        }

        if (result.size() > 0 && ((Object[])result.get(0)).length == 1)
        {
            List r = result;
            result = new ArrayList();
            for (int i = 0; i < r.size(); i++)
            {
                result.add(((Object[]) r.get(i))[0]);
            }
        }
        return result;
    }

    private Object[] result(Object obj)
    {
        state.put(candidateAlias, obj);

        Expression[] result = compilation.getExprResult();
        Object[] r = new Object[result.length];
        for (int i=0; i 0 ? set.get(0) : null);
        state.put(candidateAlias, element);

        Object[] r = new Object[result.length];
        for (int j=0; j




© 2015 - 2024 Weber Informatics LLC | Privacy Policy