alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (SelectQueryPlan.java)

This example Glassfish source code file (SelectQueryPlan.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

arraylist, arraylist, constraintfieldname, constraintnode, fielddesc, foreignfielddesc, jdbc, localfielddesc, noi18n, noi18n, retrievedescimpl, retrievedescimpl, selectqueryplan, selectqueryplan, selectstatement, sql, util

The Glassfish SelectQueryPlan.java source code

/*
 * 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.
 */

/*
 * SelectQueryPlan.java
 *
 * Created on October 3, 2001
 *
 */

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

import org.netbeans.modules.dbschema.ColumnElement;
import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
import com.sun.jdo.api.persistence.support.JDOUserException;
import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.LogHelperSQLStore;
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.PersistenceManager;
import com.sun.jdo.spi.persistence.support.sqlstore.model.*;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.ResultDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.*;
import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration;
import com.sun.jdo.spi.persistence.utility.logging.Logger;
import org.glassfish.persistence.common.I18NHelper;

import java.util.*;
import java.sql.ResultSet;
import java.sql.SQLException;


/**
 * This class prepares the generation of select statements,
 * by joining the constaint stacks of all retrieve descriptors
 * into one stack.
 */
public class SelectQueryPlan extends QueryPlan {

    /** This plan is joined with the parent plan. Used only for dependent plan. */
    private static final int ST_JOINED = 0x2;

    /** This plans's constraints are already processed. */
    public static final int ST_C_BUILT = 0x4;

    /** This plans's order by constraints are already processed. */
    public static final int ST_OC_BUILT = 0x10;

    /**
     * Pointer to the retrieve descriptor's constraint stack.
     * NOTE: The retrieve descriptor's stack will be modified
     * building the query plan!
     */
    protected Constraint constraint;

    /** Bitmask constaining OPT_* Constants defined in {@link RetrieveDescImpl } */
    public int options;

    /** Iterator for the retrieve descriptor's list of fields to be retrieved. */
    private Iterator fieldIterator;

    /**
     * Aggregate result type from the retrieve descriptor as defined by
     * {@link FieldTypeEnumeration}
     */
    private int aggregateResultType;

    /**
     * List of SelectQueryPlan. After this plan is completely built, this field
     * contains all the foreign plans that could not be joined with this plan.
     */
    private ArrayList foreignPlans;

    /**
     * This foreign field joins this plan to the parent plan. The field is from
     * config of the parent plan. Used only for dependent plan.
     */
    protected ForeignFieldDesc parentField;

    /**
     * This plan corresponds to prefetched values for <code>parentField.
     * Used only for dependent plan.
     */
    private boolean prefetched;

    private Concurrency concurrency;

    /** BitSet containing the hierarchical fetch groups to be retrieved for this plan. */
    private BitSet hierarchicalGroupMask;

    /** BitSet containing the independent fetch groups to be retrieved for this plan. */
    private BitSet independentGroupMask;

    /** BitSet containing the fields to be retrieved for this plan */
    private BitSet fieldMask;

    private Map foreignConstraintPlans;

    private ResultDesc resultDesc;

    /**
     * Takes care of adding an "And" constraint for unbound constraints, e.g.
     * "empid == department.deptid". As the foreign constraint stack is empty,
     * we would not add the necessary "And" constraint otherwise.
     */
    // See navigation033 for an example
    private boolean appendAndOp;

    /** The logger. */
    private final static Logger logger = LogHelperSQLStore.getLogger();

    /** Name of the MULTILEVEL_PREFETCH property. */
    public static final String MULTILEVEL_PREFETCH_PROPERTY =
        "com.sun.jdo.spi.persistence.support.sqlstore.MULTILEVEL_PREFETCH"; // NOI18N

    /**
     * Property to switch on multilevel prefetch. Note, that the default
     * is false, meaning that multilevel prefetch is disabled by default.
     */
    private static final boolean MULTILEVEL_PREFETCH = Boolean.valueOf(
        System.getProperty(MULTILEVEL_PREFETCH_PROPERTY, "false")).booleanValue(); // NOI18N
    
    /**
     * Creates a new instance of SelectQueryPlan depending on the retrieve
     * descriptor options.
     * @param desc The retrieve descriptor
     * @param store The store
     * @param concurrency The concurrency for the plan.
     * @return An instance of SelectQueryPlan depending on the retrieve
     * descriptor options.
     */
    public static SelectQueryPlan newInstance(RetrieveDescImpl desc,
                                              SQLStoreManager store,
                                              Concurrency concurrency) {
        SelectQueryPlan plan = null;

        if ( (desc.getOptions() & RetrieveDescImpl.OPT_VERIFY) > 0) {
            plan = new VerificationSelectPlan(desc, store);
        } else {
            plan = new SelectQueryPlan(desc, store, concurrency);
        }

        return plan;
    }

    /**
     * Creates a new SelectQueryPlan.
     *
     * @param desc Retrieve descriptor holding the query information
     *    from the query compiler. This information includes selected
     *    fields and the query constraints. <code>desc must be an
     *    instance of RetrieveDescImpl.
     * @param store Store manager executing the query.
     * @param concurrency Query concurrency.
     */
    public SelectQueryPlan(ActionDesc desc,
                           SQLStoreManager store,
                           Concurrency concurrency) {

        super(desc, store);
        action = ACT_SELECT;

        // Initialize internal fields.
        fieldMask = new BitSet();
        hierarchicalGroupMask = new BitSet();
        independentGroupMask = new BitSet();
        this.concurrency = concurrency;
        //excludeSubclasses = true;

        if (desc instanceof RetrieveDescImpl) {
            RetrieveDescImpl retrieveDesc = (RetrieveDescImpl) desc;
            retrieveDesc.setPlan(this);

            // Get the information from the retrieve descriptor.
            constraint = retrieveDesc.getConstraint();
            options = retrieveDesc.getOptions();
            fieldIterator = retrieveDesc.getFields();
            aggregateResultType = retrieveDesc.getAggregateResultType();
        } else {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                "core.generic.notinstanceof", desc.getClass().getName(), "RetrieveDescImpl")); // NOI18N
        }
    }

    public Constraint getConstraint() {
        return constraint;
    }

    private void setFieldMask(int index) {
        if (index < 0) {
            index = config.fields.size() - index;
        }

        fieldMask.set(index);
    }

    private boolean getFieldMask(int index) {
        if (index < 0) {
            index = config.fields.size() - index;
        }

        return fieldMask.get(index);
    }

    /**
     * The addTable method is used to add tables correponding to a field to the plan.
     * No columns corresponding the field are added to the plan.
     *
     * @param fieldDesc The field for which we need to add table
     */
    protected void addTable(LocalFieldDesc fieldDesc) {
        addColumn(fieldDesc, false, false);
    }

    /**
     * The addColumn method is used to specify a field for which data needs
     * to be retrieved and therefore for which we need to select a column.
     *
     * @param fieldDesc The field for which we need to retrieve data and therefore
     * for which we need to select a column.
     */
    protected void addColumn(LocalFieldDesc fieldDesc) {
        addColumn(fieldDesc, true, false);
    }

    /**
     * The addColumn method is used to specify a field for which data needs to
     * be retrieved and therefore for which we need  to select a column.
     *
     * @param fieldDesc The field for which we need to retrieve data and therefore
     * for which we need to select a column.
     * @param add Specifies if the field will be added to {@link ResultDesc}.
     * @param projection Pass the projection information for this field
     * to {@link ResultDesc}.
     */
    private void addColumn(LocalFieldDesc fieldDesc, boolean add, boolean projection) {

        // We first search to see if any of the tables to which the requested
        // field is mapped is being used by this query plan. Initially
        // there is a select statement for each table so we just append this
        // request as a column to the found statement. If none of the tables
        // are being used in this query plan then we create a new statement.
        //
        for (Iterator iter = fieldDesc.getColumnElements(); iter.hasNext(); ) {
            ColumnElement columnElement = (ColumnElement) iter.next();
            QueryTable table = findQueryTable(columnElement.getDeclaringTable());

            if (table == null)
                table = addQueryTable(columnElement.getDeclaringTable(), null);

            SelectStatement statement = (SelectStatement) getStatement(table);

            if (statement == null)
                statement = (SelectStatement) addStatement(table);

            if (add) {
                ColumnRef columnRef = statement.addColumn(columnElement, table);
                // initialize the resultDesc
                if (resultDesc == null) {
                    resultDesc = new ResultDesc(config, aggregateResultType);
                }
                resultDesc.addField(fieldDesc, columnRef, projection);
            }
        }
    }

    /**
     * Create and build the query plans for foreign fields that have been
     * added by {@link RetrieveDesc#addResult(String, RetrieveDesc, boolean)}.
     * If there is no projection, add the foreign key fields to the list
     * of fields to be selected.
     *
     * @param foreignFields List of local fields.
     * @param localFields List of fields to be selected.
     * @see RetrieveDescImpl
     */
    private void processForeignFields(ArrayList foreignFields,
                                      ArrayList localFields) {
        if (foreignFields.size() == 0) {
            return;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);

        if (debug) {
            logger.finest("sqlstore.sql.generator.selectqueryplan.processforeignfield", // NOI18N
                          config.getPersistenceCapableClass().getName());
        }

        foreignPlans = new ArrayList();

        for (int i = 0; i < foreignFields.size(); i++) {
            processForeignField((ConstraintFieldName) foreignFields.get(i), localFields);
        }

        if (debug) {
            logger.finest("sqlstore.sql.generator.selectqueryplan.processforeignfield.exit"); // NOI18N
        }
    }

    /**
     * Process the projected foreign field at index <code>index.
     * Initializes and builds a new SelectQueryPlan for this field and
     * adds selected columns to the result descriptor. If the field is
     * navigated only, just adds the statement and table alias.
     *
     * @param cfn
     * @param localFields
     */
    private void processForeignField(ConstraintFieldName cfn,
                                     ArrayList localFields) {

        SelectQueryPlan fp = new SelectQueryPlan(cfn.desc, store, concurrency);

        fp.prefetched = cfn.isPrefetched();
        if (fp.prefetched) {
            // Add fetch groups to the foreign plan if we are prefetching.
            fp.options |= RetrieveDescImpl.OPT_ADD_FETCHGROUPS;
        }

        fp.processParentField(config, cfn.name);
        fp.build();

        // For navigational queries, add in any additional local fields which
        // may be needed by this foreign field (typically the foreign keys).
        // For external (user) queries, we just make sure we include the
        // corresponding table into the table list.
        for (int i = 0; i < fp.parentField.localFields.size(); i++) {
            LocalFieldDesc la = (LocalFieldDesc) fp.parentField.localFields.get(i);

            if (!getFieldMask(la.absoluteID)) {
                if ((options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0) {
                    // Add the field to localFields only if this plan corresponds
                    // to a candidate.
                    localFields.add(la);
                } else {
                    // This plan is participating in a projection.
                    // Add the table and a corresponding statement to the plan.
                    addTable(la);
                }
            }
        }
        foreignPlans.add(fp);
    }

    private boolean getGroupMask(int groupID) {
        if (groupID >= FieldDesc.GROUP_DEFAULT)
            return hierarchicalGroupMask.get(groupID);
        else if (groupID < FieldDesc.GROUP_NONE)
            return independentGroupMask.get(-(groupID + 1));

        return true;
    }

    private void setGroupMask(int groupID) {
        if (groupID >= FieldDesc.GROUP_DEFAULT)
            hierarchicalGroupMask.set(groupID);
        else if (groupID < FieldDesc.GROUP_NONE)
            independentGroupMask.set(-(groupID + 1));
    }

    /**
     * Add the fields from the fetch group specified by <code>groupID
     * to the list of selected fields. The decision which fields are
     * added is based on the following rules:
     *
     * <ol>
     * <li>Local fields are added for all the queries and user
     *     projections, that aren't aggregates.</li>
     * <li>Only key fields are added for aggregate queries counting persistence capable objects.
     * <li>Foreign fields are added only for the projected retrieve descriptor and for
     *     queries that do not have relationsip prefetch disabled. <li>
     * </ol>
     *
     * @param groupID Fetch group id.
     * @param localFields List of fields to be selected.
     * @param foreignFields List of foreign fields connecting to foreign plans.
     */
    private void addFetchGroup(int groupID,
                               ArrayList localFields,
                               ArrayList foreignFields) {
        // We should enter this method only if OPT_ADD_FETCHGROUPS is set.
        assert (options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0;

        ArrayList group = config.getFetchGroup(groupID);
        setGroupMask(groupID);

        if (group != null) {
            for (int i = 0; i < group.size() ; i++) {
                FieldDesc f = (FieldDesc) group.get(i);

                if (!getFieldMask(f.absoluteID)) {
                    final boolean isLocalField = f instanceof LocalFieldDesc;
                    // Prevent testing field again.
                    setFieldMask(f.absoluteID);

                    if (isLocalField) {
                        if ((options & RetrieveDescImpl.OPT_ADD_KEYS_ONLY) == 0 || f.isKeyField()) {
                            // pk fields are added before any other fields already
                            // present in localFields. This is because pk fields
                            // are the first to be read when resultset is processed.
                            // Please see IN=8852 for more details.
                            // All other fields are appended to the list.
                            int indexToInsert = ( f.isKeyField() ? 0 : localFields.size() );
                            localFields.add(indexToInsert, f);
                        }
                    } else {
                        // Add foreign fields only if this plan corresponds to the
                        // projected RD and relationship prefetch is not explicitly
                        // disabled by the user.
                        if ( ((options & RetrieveDescImpl.OPT_PROJECTION) > 0 || MULTILEVEL_PREFETCH) &&
                              (options & RetrieveDescImpl.OPT_ADD_KEYS_ONLY) == 0 &&
                              (options & RetrieveDescImpl.OPT_DISABLE_RELATIONSHIP_PREFETCH) == 0 ) {
                            // Add current field to foreignFields as ConstraintFieldName
                            ForeignFieldDesc ff = (ForeignFieldDesc) f;
                            RetrieveDescImpl desc = (RetrieveDescImpl)
                                    store.getRetrieveDesc(ff.foreignConfig.getPersistenceCapableClass());
                            foreignFields.add(new ConstraintFieldName(ff.getName(), desc, true));
                        }
                    }
                }
            }
        }
    }

    /**
     * Add the fields from the fetch group specified by <code>groupID
     * to the list of selected fields. For hierarchical groups, we add all the
     * groups from GROUP_DEFAULT up to <code>groupID. For independent
     * groups, we only add the default and the group indicated by
     * <code>groupID.
     *
     * @param groupID Fetch group id.
     * @param localFields List of fields to be selected.
     * @param foreignFields List of foreign fields.
     */
    private void addFetchGroups(int groupID,
                                ArrayList localFields,
                                ArrayList foreignFields) {

        if (groupID >= FieldDesc.GROUP_DEFAULT) {
            //Hierachical fetch group
            for (int i = FieldDesc.GROUP_DEFAULT; i <= groupID; i++) {
                if (!getGroupMask(i)) {
                    addFetchGroup(i, localFields, foreignFields);
                }
            }
        } else if (groupID < FieldDesc.GROUP_NONE) {
            if (!getGroupMask(FieldDesc.GROUP_DEFAULT)) {
                //Independent fetch group
                addFetchGroup(FieldDesc.GROUP_DEFAULT, localFields, foreignFields);
            }

            if (!getGroupMask(groupID)) {
                addFetchGroup(groupID, localFields, foreignFields);
            }
        }
    }

    /**
     * Add the fetch group fields to the list of selected fields.
     * The decision if fetch groups are added is based on the following rules:
     *
     * <ul>
     * <li>Always add fetch groups for internal queries.
     * <li>For external queries, add fetch groups to the projected retrieve
     *    descriptor as marked in RetrieveDescImpl#setFetchGroupOptions(int)</li>
     * </ul>
     *
     * @param localFields List of fields to be selected.
     * @param foreignFields List of foreign fields.
     * @see RetrieveDescImpl#setFetchGroupOptions(int)
     */
     private void processFetchGroups(ArrayList localFields, ArrayList foreignFields) {

        if ((options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0) {
            int requestedItems = localFields.size() + foreignFields.size();

            // Add the default fetch group.
            if (!getGroupMask(FieldDesc.GROUP_DEFAULT)) {
                addFetchGroups(FieldDesc.GROUP_DEFAULT, localFields, foreignFields);
            }

            if (requestedItems > 0) {
                for (int i = 0; i < localFields.size(); i++) {
                    FieldDesc f = (FieldDesc) localFields.get(i);

                    setFieldMask(f.absoluteID);

                    if (f.fetchGroup != FieldDesc.GROUP_NONE) {
                        if (!getGroupMask(f.fetchGroup)) {
                            addFetchGroups(f.fetchGroup, localFields, foreignFields);
                        }
                    }
                }

                for (int i = 0; i < foreignFields.size(); i++) {
                    ConstraintFieldName cfn = (ConstraintFieldName) foreignFields.get(i);
                    FieldDesc f = config.getField(cfn.name);

                    setFieldMask(f.absoluteID);

                    if (f.fetchGroup != FieldDesc.GROUP_NONE) {
                        if (!getGroupMask(f.fetchGroup)) {
                            addFetchGroups(f.fetchGroup, localFields, foreignFields);
                        }
                    }
                }
            }
        }
    }

    /**
     * Add all requested local fields to {@link ResultDesc}.
     *
     * @param localFields List of local fields to be selected.
     * @param projectionField The projected field.
     */
    private void processLocalFields(ArrayList localFields, LocalFieldDesc projectionField) {
        boolean debug = logger.isLoggable(Logger.FINEST);

        if (debug) {
            logger.finest("sqlstore.sql.generator.selectqueryplan.processlocalfield", // NOI18N
                          config.getPersistenceCapableClass().getName());
        }

        for (int i = 0; i < localFields.size(); i++) {
            LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
            addColumn(lf, true, (projectionField == lf));
        }

        if (debug) {
            logger.finest("sqlstore.sql.generator.selectqueryplan.processlocalfield.exit"); // NOI18N
        }
    }

    private void joinSecondaryTableStatement(SelectStatement statement,
                                             SelectStatement secondaryTableStatement) {
        statement.copyColumns(secondaryTableStatement);

        QueryTable secondaryTable = (QueryTable) secondaryTableStatement.getQueryTables().get(0);
        ReferenceKeyDesc key = secondaryTable.getTableDesc().getPrimaryTableKey();

        addJoinConstraint(this, this,
                key.getReferencedKey().getColumns(),
                key.getReferencingKey().getColumns(), ActionDesc.OP_LEFTJOIN);

        secondaryTableStatement.markJoined();
    }

    private void processRelatedStatements(SelectStatement statement) {
        ArrayList secondaryTableStatements = statement.getSecondaryTableStatements();

        if (secondaryTableStatements != null) {
            for (int i = 0; i < secondaryTableStatements.size(); i++) {
                SelectStatement secondaryTableStatement = (SelectStatement) secondaryTableStatements.get(i);

                if (!secondaryTableStatement.isJoined()) {
                    processRelatedStatements(secondaryTableStatement);
                    joinSecondaryTableStatement(statement, secondaryTableStatement);
                }
            }

            secondaryTableStatements.clear();
        }
    }

    protected void processStatements() {
        boolean debug = logger.isLoggable(Logger.FINEST);

        if (debug) {
             Object[] items = new Object[] {config.getPersistenceCapableClass().getName(),
                                            new Integer(statements.size())};
             logger.finest("sqlstore.sql.generator.selectqueryplan.processstmts",items); // NOI18N
        }

        if (concurrency != null) {
            concurrency.select(this);
        }

        int size = statements.size();

        if (size > 1) {
            super.processStatements();

            for (int i = 0; i < size; i++) {
                SelectStatement s = (SelectStatement) statements.get(i);

                if (!s.isJoined())
                    processRelatedStatements(s);
            }

            // Remove all the statements that have been joined.
            for (int i = 0; i < statements.size(); i++) {
                SelectStatement s = (SelectStatement) statements.get(i);

                if (s.isJoined()) {
                    statements.remove(i);
                    i--;
                    continue;
                }
            }
        }

        if (debug) {
            logger.finest("sqlstore.sql.generator.selectqueryplan.processstmts.exit"); // NOI18N
        }
    }


    /**
     * Asociates every local constraint on the stack with it's original plan
     * and include any table that hasn't been added to the table list of the
     * corresponding original plan.
     *
     * @see ConstraintFieldName#originalPlan
     */
    private void processLocalConstraints() {
        List stack = constraint.getConstraints();

        for (int i = 0; i < stack.size(); i++) {
            ConstraintNode node = (ConstraintNode) stack.get(i);

            if (node instanceof ConstraintFieldName) {
                ConstraintFieldName fieldNode = (ConstraintFieldName) node;

                if (fieldNode.originalPlan == null) {
                    // The field has not been processed before
                    SelectQueryPlan thePlan = null;

                    if (fieldNode.desc == null) {
                        thePlan = this;
                    } else {
                        // If the field belongs to a different RetrieveDesc, we need
                        // to use the query plan associated with that RetrieveDesc.
                        RetrieveDescImpl rd = (RetrieveDescImpl) fieldNode.desc;
                        thePlan = newForeignConstraintPlan(rd, fieldNode.name);
                    }

                    fieldNode.originalPlan = thePlan;

                    // The name field is null for unrelated constraints.
                    if (fieldNode.name != null) {
                        FieldDesc field = thePlan.config.getField(fieldNode.name);

                        if (field instanceof LocalFieldDesc) {
                            // Adds the statement and table for the field.
                            // This is only required to process plans corresponding
                            // to query filters containing unbound variables
                            // e.g. setFilter("empid == d.deptid") on an employee query.

                            thePlan.addTable((LocalFieldDesc) field);
                        }
                    }
                }
            }
        }
    }

    /**
     * Returns the plan for {@link RetrieveDesc} <code>rd. If there is no
     * plan associated with <code>rd, a new plan is created.
     * If <code>fieldName is not null, the returned plan will be matched
     * with the first plan that was registered for a navigation on the field
     * or the plan's navigational id. The navigational id is used to discriminate
     * several navigations on the same field.
     *
     * @param rd Foreign retrieve descriptor.
     * @param fieldName Parent field name.
     * @return The plan for {@link RetrieveDesc} <code>rd.
     * @see RetrieveDescImpl
     */
    private SelectQueryPlan newForeignConstraintPlan(RetrieveDescImpl rd,
                                                     String fieldName) {

        SelectQueryPlan fcp = rd.getPlan();

        if (fcp == null) {
            fcp = new SelectQueryPlan(rd, store, null);
        }
        // If fieldName is null, it means that we don't know what the relationship
        // field name is yet and this query plan is a place holder.
        if (fieldName == null) {
            return fcp;
        }

        if (foreignConstraintPlans == null) {
            foreignConstraintPlans = new HashMap();
        }

        SelectQueryPlan masterPlan = null;

        Object tag = (rd.getNavigationalId() != null) ? rd.getNavigationalId() : fieldName;

        if ((masterPlan = (SelectQueryPlan) foreignConstraintPlans.get(tag)) != null) {
            // Share the tables with the master plan.
            fcp.tables = masterPlan.tables;
            fcp.foreignConstraintPlans = masterPlan.foreignConstraintPlans;
        } else {
            foreignConstraintPlans.put(tag, fcp);
            fcp.foreignConstraintPlans = new HashMap();
        }

        return fcp;
    }

    /**
     * Adds a subquery constraint for a correlated exists query to the
     * constraint stack. Also add the table alias from the subquery
     * to the local table aliases.
     *
     * @param ff The relationship field for the subquery
     * @param operation {@link ActionDesc#OP_NOTEXISTS}
     * or {@link ActionDesc#OP_EXISTS}.
     */
    private void addCorrelatedExistsQuery(ForeignFieldDesc ff, int operation) {

        Class classType = (ff.cardinalityUPB > 1) ? ff.getComponentType() : ff.getType();
        RetrieveDescImpl rd = (RetrieveDescImpl) store.getRetrieveDesc(classType);

        SelectQueryPlan subqueryPlan = new CorrelatedExistSelectPlan(rd, store, ff, this);
        subqueryPlan.build();

        // Make the tables involved in the subquery known to the parent query.
        addQueryTables(subqueryPlan.tables);

        ConstraintSubquery subqueryConstraint = new ConstraintSubquery();
        subqueryConstraint.operation = operation;
        subqueryConstraint.plan = subqueryPlan;

        constraint.stack.add(subqueryConstraint);
    }

    /**
     * Builds the constraint plan for foreign constraints on the constraint
     * stack. This method joins the current plan with all plans
     * related by foreign constraints found in the plan hierarchy.
     *
     * @see RetrieveDescImpl
     */
    private void processForeignConstraints() {
        List currentStack = constraint.getConstraints();
        constraint.stack = new ArrayList();
        int index = 0;

        while (index < currentStack.size()) {
            ConstraintNode node = (ConstraintNode) currentStack.get(index);

            if (node instanceof ConstraintForeignFieldName) {
                processForeignFieldConstraint((ConstraintForeignFieldName) node);

            } else if (node instanceof ConstraintFieldName) {
                index = processLocalFieldConstraint((ConstraintFieldName) node, currentStack, index);

            } else if (node instanceof ConstraintFieldNameSubQuery) {
                addCorrelatedInQuery((ConstraintFieldNameSubQuery) node);

            } else {
                constraint.stack.add(node);
            }

            index++;
        }
    }

    /**
     * Joins the current plan with the constraint <code>node. The constraint
     * includes the name of the parent field and the retrieve descriptor for the
     * related class. The plans will be joined with <code>OP_EQUIJOIN.
     * The constraints processed here have been added by
     * {@link RetrieveDesc#addConstraint(String, RetrieveDesc)}.
     *
     * @param node Join constraint.
     */
    private void processForeignFieldConstraint(ConstraintForeignFieldName node) {
        RetrieveDescImpl rd = (RetrieveDescImpl) node.desc;

        if (rd == null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "sqlstore.constraint.noretrievedesc", // NOI18N
                    node.name, config.getPersistenceCapableClass().getName()));
        }

        SelectQueryPlan fcp = newForeignConstraintPlan(rd, node.name);

        if ((fcp.status & ST_JOINED) == 0) {
            fcp.processParentField(config, node.name);
            // Joins on constraints always join as equijoin
            processJoin(fcp, ActionDesc.OP_EQUIJOIN);
            fcp.appendAndOp = true;
        } else {
            fcp.appendAndOp = false;
        }
    }

    /**
     * Joins unrelated constraints that have been added by
     * {@link RetrieveDesc#addConstraint(String, RetrieveDesc)} where the
     * name of the foreign field is null. Other constraints have been added by
     * {@link RetrieveDesc#addConstraint(String, int, RetrieveDesc, String)}
     *
     * @param node Join constraint.
     * @param currentStack Current (old) constraint stack.
     * @param index Index in current stack.
     */
    private int processLocalFieldConstraint(ConstraintFieldName node,
                                            List currentStack,
                                            int index) {
        if (node.desc != null) {
            SelectQueryPlan fcp = ((RetrieveDescImpl) node.desc).getPlan();

            constraint.stack.add(node);

            if ((fcp.status & ST_JOINED) == 0) {
                fcp.appendAndOp = true;
                // Local fields connecting to foreign plans
                // (non relationship constraints) are not processed here
                // because we want to join on all foreign fields first.
            } else {
                // The foreign plan has already been joined. We need
                // to add another And-constraint for
                // FieldName-constraints using the same retrieve
                // descriptor.  This is only required for query filters
                // comparing local fields from different tables,
                // e.g. setFilter("empid == department.deptid") on an
                // employee query.

                // Push the remaining operand and the operator onto the stack.
                constraint.stack.add(currentStack.get(++index));
                constraint.stack.add(currentStack.get(++index));
                if (fcp.appendAndOp) {
                    constraint.addOperation(ActionDesc.OP_AND);
                    fcp.appendAndOp = false;
                }
             }
        } else {
            index = processForeignFieldNullComparision(node, currentStack, index);
        }
        return index;
    }

    /**
     * Processes a null comparision on a foreign field.
     *
     * @param node Current node..
     * @param currentStack Current (old) constraint stack.
     * @param index Index in current stack.
     */
    private int processForeignFieldNullComparision(ConstraintFieldName node,
                                                   List currentStack,
                                                   int index) {
        boolean addCurrentNode = true;
        if (node.name != null) {
            // The name entry is null for unbound constraints.
            FieldDesc f = config.getField(node.name);

            if (f instanceof ForeignFieldDesc && (index + 1 < currentStack.size())) {
                ConstraintNode nextNode = (ConstraintNode) currentStack.get(++index);
                if ((nextNode instanceof ConstraintOperation) &&
                        ((((ConstraintOperation) nextNode).operation == ActionDesc.OP_NULL) ||
                        (((ConstraintOperation) nextNode).operation == ActionDesc.OP_NOTNULL))) {

                    processNullConstraint((ForeignFieldDesc) f, nextNode);
                } else {
                    constraint.stack.add(node);
                    constraint.stack.add(nextNode);
                }
                // Current node has been processed above.
                addCurrentNode = false;
            }
        }
        if (addCurrentNode) {
            constraint.stack.add(node);
        }
        return index;
    }

    /**
     * Handles the comparison of a relationship field with (non-) null.
     * Comparisons for non-collection relationships not mapped to jointables can be
     * optimized to comparing the foreign key columns being (non-) null. All other
     * cases lead to a nested (NOT-) EXISTS query.
     *
     * @param ff Relationship field.
     * @param nextNode Constraint operation, either for null or non-null comparison.
     */
    private void processNullConstraint(ForeignFieldDesc ff, ConstraintNode nextNode) {

        if (ff.hasForeignKey()) {
            // Optimize the query to compare the foreign key fields with null.
            ArrayList localFields = ff.getLocalFields();

            for (int j = 0; j < localFields.size(); j++) {
                constraint.stack.add(new ConstraintFieldDesc((LocalFieldDesc) localFields.get(j)));
                constraint.stack.add(nextNode);
            }
        } else {
            // Otherwise, generate a nested (NOT-) EXISTS sub query.
            int subOp = ActionDesc.OP_NOTEXISTS;

            if (((ConstraintOperation) nextNode).operation == ActionDesc.OP_NOTNULL) {
                subOp = ActionDesc.OP_EXISTS;
            }

            // Add a subquery constraint for this field
            addCorrelatedExistsQuery(ff, subOp);
        }
    }

    /**
     * Creates and builds a correlated "In" subquery.
     * Merges tables from the subquery plan to the current plan and adds
     * the local fields corresponding to the subquery to the constaints.
     * The subquery is added to the constraint stack.
     *
     * @param node subquery constraint.
     */
    private void addCorrelatedInQuery(ConstraintFieldNameSubQuery node) {
        FieldDesc field = config.getField(node.fieldName);
        RetrieveDescImpl rd = (RetrieveDescImpl) node.desc;

        if (field != null && field instanceof ForeignFieldDesc) {
            ForeignFieldDesc ff = (ForeignFieldDesc) field;

            if (ff.getComponentType() != rd.getPersistenceCapableClass() ) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.unknownfield", // NOI18N
                        node.fieldName, rd.getPersistenceCapableClass().getName()));
            }

            SelectQueryPlan subqueryPlan = new CorrelatedInSelectPlan(rd, store, ff, this);
            subqueryPlan.build();

            // Make the tables involved in the subquery known to the parent query.
            addQueryTables(subqueryPlan.tables);

            // Push a new subquery constraint on the stack
            ConstraintSubquery subqueryConstraint = new ConstraintSubquery();
            subqueryConstraint.plan = subqueryPlan;
            constraint.stack.add(subqueryConstraint);

            ArrayList localFields = ff.getLocalFields();
            // Add the local fields corresponding to the subquery to the stack.
            for (int i = 0; i < localFields.size(); i++) {
                constraint.addField((LocalFieldDesc) localFields.get(i), this);
            }
        } else {
            // We didn't get a ForeignFieldDesc from config,
            // or the field is not present in the config.
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.unknownfield", // NOI18N
                    node.fieldName, rd.getPersistenceCapableClass().getName()));
        }
    }

    /**
     * Builds the constraint plan for unbound contraints between
     * different retrieve descriptors. <em>Unbound constraints
     * do not navigate a relationship, i.e. there isn't a {@link
     * ConstraintForeignFieldName} connecting the two retrieve
     * descriptors. This method handles filters like <code>setFilter("empid ==
     * d.deptid")</code> on an employee query, where d is
     * the unbound variable.  These constraints have been added by
     * {@link RetrieveDesc#addConstraint(String, int, RetrieveDesc, String)}.
     */
    private void processUnboundConstraints() {
        List currentStack = constraint.getConstraints();
        constraint.stack = new ArrayList();

        for (int i = 0; i < currentStack.size(); i++) {
            ConstraintNode node = (ConstraintNode) currentStack.get(i);

            if (node instanceof ConstraintFieldName) {
                ConstraintFieldName fieldNode = (ConstraintFieldName) node;

                if (fieldNode.name != null) {
                    constraint.stack.add(fieldNode);
                } else if (fieldNode.desc != null) {
                    SelectQueryPlan fcp = ((RetrieveDescImpl) fieldNode.desc).getPlan();

                    // Do the join.
                    if ((fcp.status & ST_JOINED) == 0) {
                        // As this is a "real" non-relationship join,
                        // do not force the addition of an and constraint.
                        fcp.appendAndOp = false;

                        processJoin(fcp, ActionDesc.OP_NONREL_JOIN);
                    }
                }
            } else {
                constraint.stack.add(node);
            }
        }
    }

    /**
     * Builds the foreign constraint plan <code>fcp without
     * adding any new fields to {@link ResultDesc} and joins
     * the plans with the join operation <code>joinOp.
     *
     * @param fcp Foreign constraint plan.
     * @param joinOp Join operation.
     */
    private void processJoin(SelectQueryPlan fcp, int joinOp) {
        fcp.processConstraints();
        doJoin(fcp, joinOp);
    }

    /**
     * Sets the plan's parent field and adds the tables for the join columns
     * to the table list. The parent field is identified by <code>fieldName
     * and defined in the model information of the parent class
     * <code>parentConfig.
     *
     * @see ClassDesc
     */
    private void processParentField(ClassDesc parentConfig, String fieldName) {
        if (parentField == null) {
            // The plan has not been processed before
            FieldDesc f = parentConfig.getField(fieldName);

            if (f == null || !(f instanceof ForeignFieldDesc)) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.unknownfield", // NOI18N
                        fieldName, parentConfig.getPersistenceCapableClass().getName()));
            }
            parentField = (ForeignFieldDesc) f;

            // Add the join table, if neccessary.
            if (parentField.useJoinTable()) {
                // It is important to add the join table here so that this table does not
                // get lost behind the same join table in parentPlan's table list
                // See collection38
                //
                for (int i = 0; i < parentField.assocLocalColumns.size(); i++) {
                    ColumnElement col = (ColumnElement) parentField.assocLocalColumns.get(i);
                    addQueryTable(col.getDeclaringTable(), config);
                }
            }

            // Add the joined tables.
            // This is required for cases where no fields from this plan are selected
            // The side-effect for this is to create statements with no columns.
            for (int i = 0; i < parentField.foreignColumns.size(); i++) {
                ColumnElement col = (ColumnElement) parentField.foreignColumns.get(i);
                addQueryTable(col.getDeclaringTable(), config);
            }
        }
    }

    /**
     * Builds the query plan for a select type
     * {@link ActionDesc} (i.e. a {@link RetrieveDesc}).
     */
    public void build() {
        // Plan must be build only once.
        if ((status & ST_BUILT) > 0) {
            return;
        }

        processFields();

        processConstraints();

        processJoins();

        processOrderConstraints();

        status |= ST_BUILT;
   }

    /**
     * Process the fields from the retrieve descriptor's field list.
     * <em>Must be overwritten by subquery plans!
     */
    protected void processFields() {
        ArrayList foreignFields = new ArrayList();
        ArrayList localFields = new ArrayList();

        LocalFieldDesc projectionField = separateFieldList(localFields, foreignFields);

        // Because of a problem with BLOB columns on SQLServer
        // fetch group fields are added to the beginning of localFields.
        processFetchGroups(localFields, foreignFields);

        // For internal queries, processForeignFields might add additional
        // fields to localFields, so we call it first.
        processForeignFields(foreignFields, localFields);
        processLocalFields(localFields, projectionField);
    }

    /**
     * Separates the retrieve descriptor's field list. Cull out the
     * foreign field constraints into <code>foreignFields. Get
     * the field descriptors of local fields and put them into
     * <code>localFields.
     *
     * @param localFields List of LocalFieldDesc.
     * @param foreignFields List of ConstraintFieldName.
     * @return LocalFieldDesc of the projected field.
     */
    private LocalFieldDesc separateFieldList(ArrayList localFields,
                                             ArrayList foreignFields) {

        LocalFieldDesc projectionField = null;

        while (fieldIterator.hasNext()) {
            ConstraintFieldName cfn = (ConstraintFieldName) fieldIterator.next();
            FieldDesc f = config.getField(cfn.name);

            if (f == null) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.unknownfield", // NOI18N
                        cfn.name, config.getPersistenceCapableClass().getName()));
            }

            setFieldMask(f.absoluteID);

            if (cfn.desc != null) {
                foreignFields.add(cfn);
            } else {
                localFields.add(f);
                if (cfn.isProjection()) {
                    projectionField = (LocalFieldDesc) f;
                }
            }
        }

        return projectionField;
    }

    protected void processConstraints() {
        // Constraints must be build only once.
        if ((status & ST_BUILT) > 0 || (status & ST_C_BUILT) > 0) {
            return;
        }

        processLocalConstraints();

        // Join all the statements.
        processStatements();

        processForeignConstraints();

        // Joins over unbound variables.
        processUnboundConstraints();

        status |= ST_C_BUILT;
    }

    /**
     * Joins the current plan with <code>foreignPlan.
     * The join operation <code>joinOperation
     * will be added to the constraint stack.
     *
     * @param foreignPlan Query plan to be joined.
     * @param joinOperation Join operation. No join constaint is
     *  added for non relationship joins.
     */
    private void doJoin(SelectQueryPlan foreignPlan, int joinOperation) {
        if ((foreignPlan.status & ST_JOINED) > 0) {
            return;
        }

        mergeConstraints(foreignPlan, joinOperation);

        mergeStatements(foreignPlan, joinOperation);

        if (foreignPlan.tables != null) {
            addQueryTables(foreignPlan.tables);
        }

        foreignPlan.status = foreignPlan.status | ST_JOINED;
    }

    /**
     * Merge the foreign statement with us.<br />
     * If there is no foreign statement,
     * this method just returns.
     *
     * @param foreignPlan Foreign plan to be joined.
     * @param joinOperation Join operator.
     */
    private void mergeStatements(SelectQueryPlan foreignPlan, int joinOperation) {
        SelectStatement fromStatement;
        SelectStatement toStatement;

        if (foreignPlan.statements.size() > 0) {
            toStatement = (SelectStatement) foreignPlan.statements.get(0);

            // Merge the foreign query with us.
            if (statements.size() > 0) {
                fromStatement = (SelectStatement) statements.get(0);

                // Copy projected columns
                fromStatement.copyColumns(toStatement);

                // For a non relationship join, we need to add all tables from the
                // foreign statement. In any other case, the tables will be added
                // when the join operation is processed by the statement.
                if (joinOperation == ActionDesc.OP_NONREL_JOIN) {
                    fromStatement.tableList.addAll(toStatement.tableList);
                }

                mergeResultDesc(foreignPlan);
                if (foreignPlan.prefetched) {
                    // If the foreign plan is marked as a prefetched plan,
                    // propagate this information to its resultDesc.
                    resultDesc.setPrefetching();
                }

                this.options |= foreignPlan.options;
            }
        }
    }

    /**
     * Merge the foreign constraints with us.<br />
     * Adds the appropriate Join-constraint to the stack and merges
     * the constraint stacks. Adds an And-constraint, if neccessary,
     * see {@link com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.Constraint#mergeConstraint}.
     *
     * @param foreignPlan Foreign plan to be joined.
     * @param joinOperation Join operator.
     */
    private void mergeConstraints(SelectQueryPlan foreignPlan, int joinOperation) {

        if (joinOperation != ActionDesc.OP_NONREL_JOIN) {
            // Add the join constraint.
            if (foreignPlan.parentField.useJoinTable()) {
                // The join table is added to the foreign plan while processing
                // parent field
                addJoinConstraint(this, foreignPlan,
                        foreignPlan.parentField.localColumns,
                        foreignPlan.parentField.assocLocalColumns, joinOperation);

                addJoinConstraint(foreignPlan, foreignPlan,
                        foreignPlan.parentField.assocForeignColumns,
                        foreignPlan.parentField.foreignColumns, joinOperation);

                // Except for oracle, the outer join condition will end up in
                // from clause. Hence, add OP_AND for Equijoin only
                if (joinOperation == ActionDesc.OP_EQUIJOIN) {
                    constraint.addOperation(ActionDesc.OP_AND);
                }
            } else {
                addJoinConstraint(this, foreignPlan,
                        foreignPlan.parentField.localColumns,
                        foreignPlan.parentField.foreignColumns, joinOperation);
            }
        }

        // Copy the constraints from the toStack.
        boolean addAnd = constraint.mergeConstraint(foreignPlan.constraint, joinOperation);

        if (addAnd || foreignPlan.appendAndOp) {
            constraint.addOperation(ActionDesc.OP_AND);
        }
    }

    /**
     * Joins <code>foreignPlan's result
     * descriptor with the current plan.
     *
     * @param foreignPlan Query plan to be joined.
     */
    private void mergeResultDesc(SelectQueryPlan foreignPlan) {
        ResultDesc foreignResult = foreignPlan.resultDesc;

        if (resultDesc != null && foreignResult != null) {
            resultDesc.doJoin(foreignResult, foreignPlan.parentField);
        } else if (resultDesc == null) {
            resultDesc = foreignResult;
        }
    }

    /**
     * Put in a join constraint to the foreign table.
     *
     * @param fromPlan The plan for fromColumns
     * @param toPlan The plan for toColumns
     * @param fromColumns List of local columns.
     * @param toColumns List of foreign columns.
     * @param joinOp Join operation. This operation is never a non relationship join.
     */
    protected void addJoinConstraint(SelectQueryPlan fromPlan,
                                     SelectQueryPlan toPlan,
                                     ArrayList fromColumns,
                                     ArrayList toColumns,
                                     int joinOp) {

        ConstraintJoin join = new ConstraintJoin();

        join.operation = joinOp;
        join.fromColumns = fromColumns;
        join.fromPlan = fromPlan;
        join.toColumns = toColumns;
        join.toPlan = toPlan;

        constraint.addJoinConstraint(join);
    }

    /**
     * Compares the statements generated for the current plan
     * against the statements generated for foreign query plans
     * and joins any statements together which it can. This method
     * joins query plans on foreign fields that have been added by
     * {@link RetrieveDesc#addResult(String,RetrieveDesc,boolean)}.
     *
     * @see RetrieveDescImpl#buildQueryPlan(SQLStoreManager, Concurrency)
     */
    private void processJoins() {

        if (foreignPlans == null) {
            return;
        }

        for (Iterator iter = foreignPlans.iterator(); iter.hasNext(); ) {
            SelectQueryPlan fp = (SelectQueryPlan) iter.next();

            if ((fp.status & ST_JOINED) == 0) {
                // Recursively join foreign plans of the foreign plan.
                fp.processJoins();

                // TODO: We only join to foreign query plans that involve one statement.
                if (statements.size() == 1 && fp.statements.size() == 1) {
                    doJoin(fp, getJoinOperator(fp));
                }
            }

            if ((fp.status & ST_JOINED) > 0) {
                // Foreign plan has been joined
                iter.remove();
            }
        }

        // Sanity check.
        if (foreignPlans != null && foreignPlans.size() > 0) {

            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "sqlstore.sql.generator.selectqueryplan.plansnotjoined")); // NOI18N
        } else {
            foreignPlans = null;
        }
    }

    /**
     * Defines the join operator based on the projection property (and
     * the navigated relationship).  Depending on the relationship
     * cardinality the plans are joined with <code>OP_EQUIJOIN
     * or <code>OP_LEFTJOIN. Projection queries are always
     * joined with <code>OP_LEFTJOIN.)
     *
     * @param dependentPlan The dependent plan
     * @return Join Operator.
     */
    private int getJoinOperator(SelectQueryPlan dependentPlan) {
        int joinOperator;
        ForeignFieldDesc parentField = null;

        if (isProjection(this)) {
            parentField = dependentPlan.parentField;
        } else if (isProjection(dependentPlan)) {
            parentField = dependentPlan.parentField.getInverseRelationshipField();
        }

        if (parentField != null) {

            joinOperator = ActionDesc.OP_LEFTJOIN;
            // TODO: Check the parentField's cardinality?
//            if (parentField.cardinalityUPB == 1) {
//                // Join "to one" associations.
//                // There are two kinds of "to one" associations:
//                if (parentField.cardinalityLWB == 1) {
//                    // 1-1 associations: (fp.parentField.cardinalityLWB == 1)
//                    joinOperator = ActionDesc.OP_EQUIJOIN;
//                } else {
//                    // Optional associations: (fp.parentField.cardinalityLWB == 0)
//                    // The query should return an object, even if the navigated
//                    // relationship isn't set.
//                    joinOperator = ActionDesc.OP_LEFTJOIN;
//                }
//            } else { // parentField.cardinalityUPB > 1
//                // To-Many associations are always optional.
//                joinOperator = ActionDesc.OP_LEFTJOIN;
//            }
        } else {
            joinOperator = ActionDesc.OP_EQUIJOIN;
        }

        return joinOperator;
    }

    private boolean isProjection(SelectQueryPlan plan) {
        return(prefetched
                || (plan.options & RetrieveDescImpl.OPT_PROJECTION) > 0
                && (plan.options & RetrieveDescImpl.OPT_AGGREGATE) == 0);
    }

    /**
     * Converts ConstraintFieldName used in Order by constraints into
     * ConstraintFieldDesc using ConstraintFieldName#originalPlan.<br />
     *
     * <em>Currently unused functionality:
* Gets all the "order by" constraints from the the current stack. * The constraints are ordered such that any "order by" constraint * with position N is placed before any "order by" constraint with * position N+m, where m > 0. Also any "order by" constraint with * no position (i.e. position < 0) are placed immediately * following the previous "order by" constraint with a position. * The order of the "order by" constraints on the constraint stack * is changed to effect this ordering. * <em>NOTE: The value constraints giving the position for * the order by constraints is currently not generated by the * query compiler. */ public void processOrderConstraints() { if ((status & ST_BUILT) > 0 || (status & ST_OC_BUILT) > 0) { return; } ArrayList orderByArray = new ArrayList(); int i, pos; int insertAt = 0; // Now pull out all "order by" constraints and convert // ConstraintFieldName to ConstraintFieldDesc expected // by SelectStatement. if (constraint != null) { i = 0; while (i < constraint.stack.size()) { ConstraintNode opNode = (ConstraintNode) constraint.stack.get(i); if ((opNode instanceof ConstraintOperation) && ((((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY) || (((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY_DESC))) { pos = -1; if ((i > 1) && (constraint.stack.get(i - 2) instanceof ConstraintValue)) { pos = ((Integer) ((ConstraintValue) constraint.stack.get(i - 2)).getValue() ).intValue(); constraint.stack.remove(i - 2); i = i - 1; } if (pos > 0) { insertAt = pos; } for (int k = orderByArray.size(); k <= insertAt; k++) { orderByArray.add(null); } if (orderByArray.get(insertAt) == null) { orderByArray.set(insertAt, new ArrayList()); } ConstraintNode fieldNode = (ConstraintNode) constraint.stack.get(i - 1); ConstraintFieldDesc consFieldDesc = null; if (fieldNode instanceof ConstraintFieldName) { QueryPlan originalPlan = this; if (((ConstraintField) fieldNode).originalPlan != null) { originalPlan = ((ConstraintField) fieldNode).originalPlan; } FieldDesc fieldDesc = originalPlan.config. getField(((ConstraintFieldName) fieldNode).name); if (!(fieldDesc instanceof LocalFieldDesc)) { throw new JDOUserException(I18NHelper.getMessage(messages, "core.generic.notinstanceof", // NOI18N fieldDesc.getClass().getName(), "LocalFieldDesc")); // NOI18N } consFieldDesc = new ConstraintFieldDesc((LocalFieldDesc) fieldDesc, originalPlan, 1); } else if (fieldNode instanceof ConstraintFieldDesc) { consFieldDesc = (ConstraintFieldDesc) fieldNode; } else { throw new JDOUserException(I18NHelper.getMessage(messages, "core.generic.notinstanceof", // NOI18N fieldNode.getClass().getName(), "ConstraintFieldName/ConstraintFieldDesc")); // NOI18N } if (((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY_DESC) { consFieldDesc.ordering = -1; } // Remember constraint in orderByArray. ArrayList temp = (ArrayList) (orderByArray.get(insertAt)); temp.add(consFieldDesc); constraint.stack.remove(i); constraint.stack.remove(i - 1); i = i - 2 + 1; } i = i + 1; } } for (int j = 0, size = orderByArray.size(); j < size; j++) { ArrayList oa = (ArrayList) orderByArray.get(j); if (constraint == null) { constraint = new Constraint(); } for (int k = 0, sizeK = oa.size(); k < sizeK; k++) { ConstraintFieldDesc ob = (ConstraintFieldDesc) oa.get(k); if (ob.ordering < 0) { constraint.addField(ob); constraint.addOperation(ActionDesc.OP_ORDERBY_DESC); } else { constraint.addField(ob); constraint.addOperation(ActionDesc.OP_ORDERBY); } } } status |= ST_OC_BUILT; } protected Statement newStatement() { return new SelectStatement(store.getVendorType(), this); } /** * Extract data from given <code>resultData * @param pm The PersistenceManager. * @param resultData The result set from which data is to be extracted. * @return Result from the given <code>resultData * @throws SQLException */ public Object getResult(PersistenceManager pm, ResultSet resultData) throws SQLException{ return resultDesc.getResult(pm, resultData); } }

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish SelectQueryPlan.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.