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

com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl Maven / Gradle / Ivy

There is a newer version: 6.2024.6
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * RetrieveDescImpl.java
 *
 * Created on March 3, 2000
 *
 */

package com.sun.jdo.spi.persistence.support.sqlstore.sql;

import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.RetrieveDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager;
import com.sun.jdo.spi.persistence.support.sqlstore.model.ClassDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.Constraint;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintFieldName;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan;
import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration;
import com.sun.jdo.spi.persistence.utility.ParameterInfo;
import org.glassfish.persistence.common.I18NHelper;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ResourceBundle;

/**
 */
public class RetrieveDescImpl extends Object implements RetrieveDesc, Cloneable {

    private static final int OPINFO_FIELD_DISALLOWED =  0x01; // 1

    private static final int OPINFO_FIELD_REQUIRED =    0x02; // 2

    private static final int OPINFO_VAL_DISALLOWED =    0x04; // 4

    private static final int OPINFO_VAL_REQUIRED =      0x08; // 8

    private static final int OPINFO_VAL_IS_PCOUNT =     0x10; // 16

    private static final int OPINFO_ILLEGAL =           0x20; // 32

    private static final int OPINFO_NO_OPERATION =      0x40; // 64

    /** Indicates, that the query projects on this RD. */
    public static final int OPT_PROJECTION =    0x1; // 1

    /** Indicates, that a distinct query should be run. */
    public static final int OPT_DISTINCT =      0x2; // 2

    /** Indicates, that the selected rows should be locked for update. */
    public static final int OPT_FOR_UPDATE =    0x4; // 4

    /** Indicates, that an avg aggregate query should be run. */
    public static final int OPT_AVG =           0x08; // 8

    /** Indicates, that a min aggregate query should be run. */
    public static final int OPT_MIN =           0x10; // 16

    /** Indicates, that a max aggregate query should be run. */
    public static final int OPT_MAX =           0x20; // 32

    /** Indicates, that a sum aggregate query should be run. */
    public static final int OPT_SUM =           0x40; // 64

    /** Indicates, that a count aggregate query should be run. */
    public static final int OPT_COUNT =         0x80; // 128

    /** Special treatment for count on persistent capable objects. */
    public static final int OPT_COUNT_PC =      0x100; // 256

    /** Sum of all aggregate options. */
    public static final int OPT_AGGREGATE = OPT_AVG + OPT_MIN + OPT_MAX +
            OPT_SUM + OPT_COUNT + OPT_COUNT_PC;

    /** Sum of all aggregate options excluding count on persistent capable objects. */
    public static final int OPT_AGGREGATE_NON_COUNT_PC = OPT_AGGREGATE - OPT_COUNT_PC;

    /** Indicates, that fetch group fields should be added. */
    public static final int OPT_ADD_FETCHGROUPS = 0x200; // 512

    /**
     * Indicates, that only key fields should be added. When this option is set,
     * it modifies meaning of OPT_ADD_FETCHGROUPS. It is assumed that
     * only key fieldes from the fetch group will be added.
     */
    public static final int OPT_ADD_KEYS_ONLY = 0x400; // 1024

    /**
     * Indicates, that even if relationship fields are in DFG, they should not
     * be prefetched. The runtime will attempt to fetch relationhip fields only
     * when OPT_ADD_FETCH_GROUPS is set.
     * @see #OPT_ADD_FETCHGROUPS
     * @see #OPT_ADD_KEYS_ONLY
     */
    public static final int OPT_DISABLE_RELATIONSHIP_PREFETCH =    0x800; // 2048

    /** Indicates special treatment for version consistency verifications. */
    public static final int OPT_VERIFY =       0x1000; // 4024

    /** Array of ConstraintFieldName. */
    private ArrayList fields;

    /** The constraint stack */
    private Constraint constraint;

    /** Bitmask of options for this instance as specified by the OPT_* constants */
    private int options;

    /** Candidate class of this instance */
    private Class pcClass;

    /** Config for candidate class of this instance */
    private ClassDesc config;

    /** SelectQueryPlan for this instance */
    private SelectQueryPlan plan;

    /**
     * Discriminates different retrieve descriptors which use the same
     * navigational field.
     */
    private Object navigationalId;

    /** Result type for an aggregate query. */
    private int aggregateResultType = FieldTypeEnumeration.NOT_ENUMERATED;

    /**
     * I18N message handler
     */
    private final static ResourceBundle messages = I18NHelper.loadBundle(
            "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
            RetrieveDescImpl.class.getClassLoader());

    public RetrieveDescImpl(Class pcClass, ClassDesc config) {
        super();

        this.pcClass = pcClass;
        this.config = config;
        fields = new ArrayList();
        constraint = new Constraint();
    }

    /**
     * The addResult method is used to specify which fields should be
     * returned in a persistent object. If the field requested is a
     * reference to another persistent object then a RetrieveDesc may be
     * provided which describes which fields of the referenced object
     * should be returned and, optionally, constraints on it.
     * If the parameter projection is true, the field
     * specified by name should be projected.
     *
     * @param name The name of the field to return.
     * @param foreignConstraint
     * RetrieveDesc describing fields and constraints for a referenced object.
     * @param projection Specifies, if this is a projection.
     */
    public void addResult(String name,
                          RetrieveDesc foreignConstraint,
                          boolean projection) {
        ConstraintFieldName cfName = new ConstraintFieldName(name, foreignConstraint);

        if (projection) {
            if ((options & OPT_PROJECTION) > 0) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "sqlstore.retrievedesc.toomanyprojections")); // NOI18N
            }

            // For projections on foreign fields, mark the foreign constraint.
            // For local fields, set the property on the field constraint.
            if (foreignConstraint != null) {
                ((RetrieveDescImpl) foreignConstraint).options |= OPT_PROJECTION;
            } else {
                cfName.setProjection();

                // Set this property if you want to have DFG fields added for
                // projections on local fields.
                //      options = options | OPT_PROJECTION;
            }
        }
        fields.add(cfName);
    }

    /**
     * The addResult method can be used to specify global
     * query attributes that don't end up in the where clause.
     * Aggregate functions and the distinct op code are examples for
     * those query options. The result type defines the object to be
     * returned by an aggregate query. In case of distinct the result
     * type should be FieldTypeEnumeration.NOT_ENUMERATED. The method
     * might be called twice, in case of a JDOQL query having both an
     * aggregate and distinct:
     * query.setResult("avg (distinct salary)");
     * ->
     * retrieveDesc.addResult(OP_AVG, FieldTypeEnumeration.DOUBLE);
     * retrieveDesc.addResult(OP_DISTINCT, FieldTypeEnumeration.NOT_ENUMERATED);
     * retrieveDesc.addResult("salary", null, true);
     *
     * @param opCode The operation code.
     * @param aggregateResultType The object type returned by aggregate queries.
     * @see com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration
     */
    public void addResult(int opCode, int aggregateResultType) {
        switch (opCode) {
            case ActionDesc.OP_DISTINCT:
                options = options | OPT_DISTINCT;
                break;
            case ActionDesc.OP_AVG:
                options = options | OPT_AVG;
                break;
            case ActionDesc.OP_MIN:
                options = options | OPT_MIN;
                break;
            case ActionDesc.OP_MAX:
                options = options | OPT_MAX;
                break;
            case ActionDesc.OP_SUM:
                options = options | OPT_SUM;
                break;
            case ActionDesc.OP_COUNT:
                options = options | OPT_COUNT;
                break;
            case ActionDesc.OP_COUNT_PC:
                options = options | OPT_COUNT_PC;
                break;
            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", "" + opCode)); // NOI18N
        }

        if (aggregateResultType != FieldTypeEnumeration.NOT_ENUMERATED) {
            if (this.aggregateResultType == FieldTypeEnumeration.NOT_ENUMERATED) {
                this.aggregateResultType = aggregateResultType;
            } else {
                // aggregate result type has already been set
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "sqlstore.retrievedesc.toomanyresulttypes")); // NOI18N
            }
        }
    }

    /**
     * Add a field specified by name to the list of fields to be prefetched.
     * @param name Name of the field to be prefetched.
     * @param foreignConstraint This parameter is null if the field is a local field.
     * If the field is a foreign field, this parameter should be not null and must refer
     * to an instance of RetrieveDesc correpsonding to the config of the foreign field.
     */
    public void addPrefetchedField(String name, RetrieveDesc foreignConstraint) {
        fields.add(new ConstraintFieldName(name, foreignConstraint, true));
    }

    /**
     * {@inheritDoc}
     */
    public void setPrefetchEnabled(boolean prefetchEnabled) {
        if (!prefetchEnabled) {
            options |= OPT_DISABLE_RELATIONSHIP_PREFETCH;
        } else {
            // options has the flag OPT_DISABLE_RELATIONSHIP_PREFETCH unset by default
        }
    }

    /**
     * 

Adds a constraint on the foreign field specified by * name. This method is used to specify a relationship * navigation on field name to the class represented by * the retrieve descriptor foreignConstraint. * If name is null, an unrelated constraint is added. * A constraint is unrelated, if there is neither a foreign field * nor a local field connecting to the retrieve descriptor * foreignConstraint. */ public void addConstraint(String name, RetrieveDesc foreignConstraint) { if (name == null) { constraint.addField(null, foreignConstraint); } else { constraint.addForeignField(name, foreignConstraint); } } /** *

Adds a constraint on the relationship field specified by * name. * This method is useful e.g. for comparisons of local fields with field of a related object: * emp.addConstraint("lastName", ActionDesc.OP_EQ, mgr, lastName"); * compares the employee's lastName field with the lastName field of the related manager. */ public void addConstraint(String name, int operation, RetrieveDesc foreignConstraint, String foreignName) { constraint.addField(foreignName, foreignConstraint); constraint.addField(name, null); constraint.addOperation(operation); } /** * The addConstraint method is used to limit the values of fields for * objects being selected. * addConstraint pushes the value, name, and operation onto the * Constraint stack. The constraints are anded together by default. * Arbitrarily complex relationships on the Constraint stack are supported. * The Constraint stack can be manipulated directly if necessary. * * @param name * The name parameter specifies the field whose value * should be limited. * @param operation * The operation parameter specifies the relationship the field * should bear to the value. Values for operation are defined in * the ActionDesc interface. * @param value * The value parameter usually specifies the value to which the * field should be limited, however it is sometimes used to * hold a parameter count as for the OP_IN operation. */ public void addConstraint(String name, int operation, Object value) { int info = getOperationInfo(operation); if ((info & OPINFO_ILLEGAL) > 0) { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "core.constraint.illegalop", "" + operation)); // NOI18N } else if ((info & OPINFO_FIELD_REQUIRED) > 0 && name == null) { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "core.constraint.fieldrequired", "" + operation)); // NOI18N } else if ((info & OPINFO_FIELD_DISALLOWED) > 0 && name != null) { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "core.constraint.fielddisallowed", "" + operation)); // NOI18N } else if ((info & OPINFO_VAL_REQUIRED) > 0 && value == null) { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "core.constraint.valrequired", "" + operation)); // NOI18N } else if ((info & OPINFO_VAL_DISALLOWED) > 0 && value != null) { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "core.constraint.valdisallowed", "" + operation)); // NOI18N } if ((info & OPINFO_VAL_IS_PCOUNT) > 0) { if (name != null) { constraint.addField(name, null); } addValueConstraint(name, value); } else { switch (operation) { case RetrieveDescImpl.OP_PARAMETER: addParameterConstraint(value); break; case ActionDesc.OP_IN: case ActionDesc.OP_NOTIN: constraint.addConstraintFieldSubQuery(name,(ActionDesc) value); break; default: if (value != null) { addValueConstraint(name, value); } if (name != null) { constraint.addField(name, null); } break; } } if ((info & OPINFO_NO_OPERATION) == 0) { constraint.addOperation(operation); } } /** * Add Constraints corresponding to given fields. * The constraints are added as Parameter Constraints. * index of the parameter starts at given startIndex * @param fields fields for which constraints are to be added. * @param startIndex starting Index for the parameter. */ public void addParameterConstraints(LocalFieldDesc[] fields, int startIndex) { for (int i = 0; i < fields.length; i++) { LocalFieldDesc field = fields[i]; addParameterConstraint(field, i + startIndex); } } /** * Add ParameterConstraint corresponding to given field * at given index. * @param field The field for which constraints are to be added. * @param index Index at which the ParameterConstraint is to be inserted. */ public void addParameterConstraint(LocalFieldDesc field, int index) { // Generate parameter info for this parameter. String fieldName = field.getName(); int type = field.getEnumType(); addConstraint(null, ActionDesc.OP_PARAMETER,new ParameterInfo(index, type, fieldName)); addConstraint(fieldName, ActionDesc.OP_FIELD, null); addConstraint(null, ActionDesc.OP_EQ, null); } /** * Adds information about value on the constraint stack. * @param name Name of the field to which the specified value is bound. * The query compiler can detect the correct value for name only in * case of simple expressions in the filter. A simple expression is * fieldName op value. If the compiler is not able to detect * correct value for name it will pass null. * @param value value to which the field's value is constrained. */ private void addValueConstraint(String name, Object value) { constraint.addValue(value, getLocalFieldDesc(name)); } /** * Adds information about parameter on the constraint stack. * @param value Instance of * com.sun.jdo.spi.persistence.utility.ParameterInfo. * Contains index, type and name of the field to which * this parameter is bound. The field name is used when binding * the parameter to the sql statement. * name can be null for complex expressions in a filter as described in * addValueConstraint. * @see #addValueConstraint */ private void addParameterConstraint(Object value) { if (value instanceof ParameterInfo) { ParameterInfo parameterInfo = (ParameterInfo)value; constraint.addParamIndex(parameterInfo.getIndex(), parameterInfo.getType(), getLocalFieldDesc(parameterInfo.getAssociatedField())); } else { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "core.constraint.illegalParameterInfo")); // NOI18N } } /** * Returns the local field descriptor for the field name. * Delegates to ClassDesc#getLocalFieldDesc(String). * * @param name Field name. * @return null if the name is null. * LocalFieldDesc for the field name otherwise. */ private LocalFieldDesc getLocalFieldDesc(String name) { return name == null ? null : config.getLocalFieldDesc(name); } /** * The getOperationInfo method returns information about the operation * requested. The following constants define different properties of * an operation and can be or'd together: * OPINFO_FIELD_DISALLOWED A field parameter cannot be specified * with this operation * OPINFO_FIELD_REQUIRED A field parameter must be specified * with this operation * OPINFO_VAL_DISALLOWED A value parameter cannot be specified * with this operation * OPINFO_VAL_REQUIRED A value parameter must be specified * with this operation * OPINFO_NULL This operation is a "null" type operation * (i.e. "is null", or "is not null") * OPINFO_ILLEGAL This operation is illegal * OPINFO_NO_OPERATION This isn't an operation at all, * it is some other specifier. * OPINFO_VAL_IS_PCOUNT This operation has a value which is the * parameter count of following parameter * nodes * * @param operation * The operation parameter specifies the operation for which * information is desired. */ private static int getOperationInfo(int operation) { int info; switch (operation) { case ActionDesc.OP_ABS: info = OPINFO_VAL_DISALLOWED; break; case ActionDesc.OP_ADD: info = 0; break; case ActionDesc.OP_AND: info = 0; break; case ActionDesc.OP_FIELD: info = OPINFO_FIELD_REQUIRED | OPINFO_VAL_DISALLOWED | OPINFO_NO_OPERATION; break; case ActionDesc.OP_BETWEEN: info = 0; break; case ActionDesc.OP_DIV: info = 0; break; case ActionDesc.OP_EQ: info = 0; break; case ActionDesc.OP_NE: info = 0; break; case ActionDesc.OP_EQUIJOIN: info = 0; break; case ActionDesc.OP_NOT: info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_DISALLOWED; break; case ActionDesc.OP_GE: info = 0; break; case ActionDesc.OP_GT: info = 0; break; case ActionDesc.OP_IN: case ActionDesc.OP_NOTIN: info = OPINFO_FIELD_REQUIRED | OPINFO_VAL_REQUIRED; break; case ActionDesc.OP_LE: info = 0; break; case ActionDesc.OP_LEFTJOIN: info = 0; break; case ActionDesc.OP_LENGTH: info = OPINFO_VAL_DISALLOWED; break; case ActionDesc.OP_LIKE: info = 0; break; case ActionDesc.OP_LIKE_ESCAPE: info = 0; break; case ActionDesc.OP_LT: info = 0; break; case ActionDesc.OP_LTRIM: info = OPINFO_VAL_DISALLOWED; break; case ActionDesc.OP_MUL: info = 0; break; case ActionDesc.OP_OR: info = 0; break; case ActionDesc.OP_ORDERBY: info = 0; break; case ActionDesc.OP_ORDERBY_DESC: info = 0; break; case ActionDesc.OP_PARAMETER_COUNT: info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_VAL_IS_PCOUNT | OPINFO_NO_OPERATION; break; case ActionDesc.OP_RIGHTJOIN: info = 0; break; case ActionDesc.OP_RTRIM: info = OPINFO_VAL_DISALLOWED; break; case ActionDesc.OP_SQRT: info = OPINFO_VAL_DISALLOWED; break; case ActionDesc.OP_SUB: info = 0; break; case ActionDesc.OP_SUBSTRING: info = 0; break; case ActionDesc.OP_POSITION: info = 0; break; case ActionDesc.OP_POSITION_START: info = 0; break; case ActionDesc.OP_MAYBE_NULL: info = OPINFO_FIELD_REQUIRED; break; case ActionDesc.OP_CONCAT: info = 0; break; case ActionDesc.OP_VALUE: info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_NO_OPERATION; break; case ActionDesc.OP_PARAMETER: info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_NO_OPERATION; break; case OP_NULL: case OP_NOTNULL: info = 0; break; case ActionDesc.OP_MOD: info = 0; break; default: info = OPINFO_ILLEGAL; break; } return info; } /** * Builds the internal query plan and initializes the select statements. * Projections on collection fields will not be resolved until the actual * retrieval in {@link SQLStoreManager#retrieve( * com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager, * RetrieveDesc, com.sun.jdo.spi.persistence.support.sqlstore.ValueFetcher)}. */ public synchronized SelectQueryPlan buildQueryPlan(SQLStoreManager store, Concurrency concurrency) { if (plan == null) { handleProjection(); plan = SelectQueryPlan.newInstance(this, store, concurrency); plan.build(); // Generate the text for the select statements. ArrayList statements = plan.getStatements(); // Sanity check. if (statements.size() > 1) { throw new JDOFatalInternalException(I18NHelper.getMessage(messages, "sqlstore.retrievedesc.stmntsnotjoined")); // NOI18N } } return plan; } /** * Sets the fetch group options for all retrieve descriptors in the * retrieve descriptor hierarchy. This is important for projection and * aggregate queries, as we don't want to select additional fields * from the data store. This is also important for queries where relationship * prefetch is involved, as we want to propagate user's choice to disable * relationship prefetch for a finder to all the retrieve descriptors in * the projection tree. * Also sets the projection on the candidate class in case of queries without * user projection. */ private void handleProjection() { // Prepare all the query options that need to be distributed to all the // RetrieveDescs involved in the projection tree. final int queryOptions = options & (OPT_AGGREGATE | OPT_DISABLE_RELATIONSHIP_PREFETCH); RetrieveDescImpl projectedDesc = distributeQueryOptions( queryOptions, aggregateResultType); if (projectedDesc == null) { // Set the default projection on the candidate retrieve descriptor. options |= OPT_PROJECTION; // Prepare fetch group options again after default projection has been set. setFetchGroupOptions(queryOptions); } } /** * Marks each descriptor with the options queryOptions and * finds the projection in the retrieve descriptor hierarchy. * The query options have to be known for each descriptor, because we don't want to * generate outer joins for OPT_COUNT_PC and we want to propagate users * choice to disable prefetch for a finder to projected RetrieveDesc. * This method relies on the fact, that each query can have only * one projection. * * @param queryOptions The options that need to be set on all * retrieve descriptors. This helps identify aggregate queries, see * {@link SelectQueryPlan#processJoins()}. * This also helps propagate user's choice to disable prefetch to the * projected RetrieveDesc, see * {@link SelectQueryPlan#addFetchGroup(int, java.util.ArrayList, java.util.ArrayList)}. * @param aggregateResultType The aggregate result type has to * be set on the projected retrieve descriptor. * @return The projected retrieve descriptor, or null there is * no projection. */ private RetrieveDescImpl distributeQueryOptions(int queryOptions, int aggregateResultType) { RetrieveDescImpl projectedDesc = null; if ((options & OPT_PROJECTION) > 0) { // This is a foreign field projection. // Set the fetch group properties. setFetchGroupOptions(queryOptions); this.aggregateResultType = aggregateResultType; projectedDesc = this; } // Distribute the aggregate option to all retrieve descriptors. options |= queryOptions; // Loop through all dependent retrieve descriptors in the field list. for (int i = 0; i < fields.size(); i++) { ConstraintFieldName cfn = (ConstraintFieldName) fields.get(i); if (cfn.isProjection()) { // This is a local field projection. // No fetch groups are added. this.aggregateResultType = aggregateResultType; projectedDesc = this; } else if (cfn.desc != null) { projectedDesc = ((RetrieveDescImpl) cfn.desc).distributeQueryOptions( queryOptions, aggregateResultType); } } return projectedDesc; } /** * Sets the fetch group policy for the projected retrieve descriptor. * The policy is based on the following rules: * *

    *
  • Fetchgroups are added for a projection w/o aggregates.
  • *
  • Only keys are added for count(*) queries.
  • *
* * @param queryOptions The quey options that needs to be set for ******** * queryOptions Aggregate queries impose * special restrictions on which fields to be selected. All aggregate * queries except count(*) operate on exactly one field. Count(*) * queries operate on persistence capable objects. * @see SelectQueryPlan#processFetchGroups(ArrayList, ArrayList) */ private void setFetchGroupOptions(int queryOptions) { if ((queryOptions & OPT_AGGREGATE_NON_COUNT_PC) == 0) { // Don't add fetch groups except for projections // w/o aggregates or counts on persistence capable objects. options |= OPT_ADD_FETCHGROUPS; if (queryOptions == OPT_COUNT_PC) { options |= OPT_ADD_KEYS_ONLY; } } } /** * Sets a navigational id on the retrieve descriptor. This id * will be used to discriminate different retrieve descriptors which * use the same navigational field. If not set, the field name is used. * * @param navigationalId Tag to discriminate different retrieve * descriptors that use the same navigational field. */ public void setNavigationalId(Object navigationalId) { this.navigationalId = navigationalId; } /** * Returns the navigational id of this retrieve descriptor. This id * will be used to discriminate different retrieve descriptors which * use the same navigational field. If not set, the field name is used. * * @return Tag to discriminate different retrieve descriptors that * use the same navigational field. */ public Object getNavigationalId() { return navigationalId; } /** * Sets option option. Only used to mark this * retrieve descriptor as internal. All valid options are defined * in this class. * * @param option Option being set. */ public void setOption(int option) { this.options |= option; } /** * Returns the result type for aggregate queries. */ public int getAggregateResultType() { return aggregateResultType; } /** * Returns the options of this retrieve descriptor. * * @return The options of this retrieve descriptor. */ public int getOptions() { return options; } public SelectQueryPlan getPlan() { return plan; } public ClassDesc getConfig() { return config; } public void setPlan(SelectQueryPlan plan) { this.plan = plan; } public Class getPersistenceCapableClass() { return pcClass; } public Constraint getConstraint() { return constraint; } public Iterator getFields() { return fields.iterator(); } public Object clone() { try { RetrieveDescImpl clone = (RetrieveDescImpl) super.clone(); clone.fields = new ArrayList(); clone.constraint = new Constraint(); return clone; } catch (CloneNotSupportedException e) { // // shouldn't happen. // return null; } } }