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

oracle.toplink.essentials.internal.expressions.QueryKeyExpression Maven / Gradle / Ivy

There is a newer version: 2.1-60f
Show newest version
/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the "License").  You may not use this file except
 * in compliance with the License.
 *
 * You can obtain a copy of the license at
 * glassfish/bootstrap/legal/CDDLv1.0.txt or
 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * HEADER in each file and include the License file at
 * glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable,
 * add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your
 * own identifying information: Portions Copyright [yyyy]
 * [name of copyright owner]
 */

// Copyright (c) 1998, 2007, Oracle. All rights reserved.  
package oracle.toplink.essentials.internal.expressions;

import java.io.*;
import java.util.*;
import oracle.toplink.essentials.descriptors.FetchGroupManager;
import oracle.toplink.essentials.exceptions.*;
import oracle.toplink.essentials.expressions.*;
import oracle.toplink.essentials.internal.helper.*;
import oracle.toplink.essentials.mappings.*;
import oracle.toplink.essentials.mappings.foundation.AbstractDirectMapping;
import oracle.toplink.essentials.queryframework.*;
import oracle.toplink.essentials.querykeys.*;
import oracle.toplink.essentials.internal.sessions.AbstractRecord;
import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
import oracle.toplink.essentials.internal.sessions.AbstractSession;
import oracle.toplink.essentials.descriptors.ClassDescriptor;

/**
 * Represents expression on query keys or mappings.
 * This includes direct, relationships query keys and mappings.
 */
public class QueryKeyExpression extends ObjectExpression {

    /** The name of the query key. */
    protected String name;

    /** Cache the aliased field. Only applies to attributes. */
    protected DatabaseField aliasedField;

    /** Is this a query across a 1:many or many:many relationship. Does not apply to attributes. */
    protected boolean shouldQueryToManyRelationship;
    
    /** Cache the query key for performance. Store a boolean so we don't repeat the search if there isn't one. */
    transient protected QueryKey queryKey;
    protected boolean hasQueryKey;

    /** Same for mappings. */
    transient protected DatabaseMapping mapping;
    protected boolean hasMapping;

    public QueryKeyExpression() {
        this.shouldQueryToManyRelationship = false;
        this.hasQueryKey = true;
        this.hasMapping = true;
    }

    public QueryKeyExpression(String aName, Expression base) {
        super();
        name = aName;
        baseExpression = base;
        shouldUseOuterJoin = false;
        shouldQueryToManyRelationship = false;
        hasQueryKey = true;
        hasMapping = true;
    }

    /**
     * INTERNAL:
     * Return the expression to join the main table of this node to any auxiliary tables.
     */
    public Expression additionalExpressionCriteria() {
        if (getDescriptor() == null) {
            return null;
        }

        Expression criteria = getDescriptor().getQueryManager().getAdditionalJoinExpression();
        if (criteria != null) {
            criteria = getBaseExpression().twist(criteria, this);
            if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
                criteria.convertToUseOuterJoin();
            }
        }

        if(getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
            if(isUsingOuterJoinForMultitableInheritance()) {
                Expression childrenCriteria = getDescriptor().getInheritancePolicy().getChildrenJoinExpression();
                childrenCriteria = getBaseExpression().twist(childrenCriteria, this);
                childrenCriteria.convertToUseOuterJoin();
                if(criteria == null) {
                    criteria = childrenCriteria;
                } else {
                    criteria = criteria.and(childrenCriteria);
                }
            }
        }

        return criteria;
    }

    /**
     * INTERNAL:
     * Used in case outer joins should be printed in FROM clause.
     * Each of the additional tables mapped to expressions that joins it.
     */
    public Map additionalExpressionCriteriaMap() {
        if (getDescriptor() == null) {
            return null;
        }

        HashMap tablesJoinExpressions = new HashMap();
        Vector tables = getDescriptor().getTables();
        // skip the main table - start with i=1
        int tablesSize = tables.size();
        if(shouldUseOuterJoin()) {
            for( int i=1; i < tablesSize; i++) {
                DatabaseTable table = (DatabaseTable)tables.elementAt(i);
                Expression joinExpression = (Expression)getDescriptor().getQueryManager().getTablesJoinExpressions().get(table);
                joinExpression = getBaseExpression().twist(joinExpression, this);
                tablesJoinExpressions.put(table, joinExpression);
            }
        }
        if(isUsingOuterJoinForMultitableInheritance()) {
            List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables();
            tablesSize = childrenTables.size();
            for( int i=0; i < tablesSize; i++) {
                DatabaseTable table = (DatabaseTable)childrenTables.get(i);
                Expression joinExpression = (Expression)getDescriptor().getInheritancePolicy().getChildrenTablesJoinExpressions().get(table);
                joinExpression = getBaseExpression().twist(joinExpression, this);
                tablesJoinExpressions.put(table, joinExpression);
            }
        }
        
        return tablesJoinExpressions;
    }

    /**
     * INTERNAL:
     * Find the alias for a given table
     */
    public DatabaseTable aliasForTable(DatabaseTable table) {
        if (isAttribute() || ((getMapping() != null) && (getMapping().isAggregateObjectMapping() || getMapping().isTransformationMapping()))) {
            return ((DataExpression)getBaseExpression()).aliasForTable(table);
        }

        //"ref" and "structure" mappings, no table printed in the FROM clause, need to get the table alias form the parent table
        if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
            DatabaseTable alias = getBaseExpression().aliasForTable((DatabaseTable)getMapping().getDescriptor().getTables().firstElement());
            alias.setName(alias.getName() + "." + getMapping().getField().getName());
            return alias;
        }

        return super.aliasForTable(table);
    }

    /**
     * INTERNAL:
     * Used for debug printing.
     */
    public String descriptionOfNodeType() {
        return "Query Key";
    }

    /**
     * INTERNAL:
     */
    public void doQueryToManyRelationship() {
        shouldQueryToManyRelationship = true;
    }

    /**
     * INTERNAL:
     * Return the field appropriately aliased
     */
    public DatabaseField getAliasedField() {
        if (aliasedField == null) {
            initializeAliasedField();
        }
        return aliasedField;

    }

    /**
     * Return the alias for our table
     */
    protected DatabaseTable getAliasedTable() {
        DataExpression base = (DataExpression)getBaseExpression();

        DatabaseTable alias = base.aliasForTable(getField().getTable());
        if (alias == null) {
            return getField().getTable();
        } else {
            return alias;
        }
    }

    /**
     * INTERNAL:
     * Return the descriptor which contains this query key.
     */
    public ClassDescriptor getContainingDescriptor() {
        return ((DataExpression)getBaseExpression()).getDescriptor();
    }

    /**
     * INTERNAL:
     */
    public DatabaseField getField() {
        if (!isAttribute()) {
            return null;
        }

        return getContainingDescriptor().getObjectBuilder().getFieldForQueryKeyName(getName());
    }

    /**
     * INTERNAL:
     * Return all the fields
     */
    public Vector getFields() {
        if (isAttribute()) {
            Vector result = new Vector(1);
            DatabaseField field = getField();
            if (field != null) {
                result.addElement(field);
            }
            return result;
        } else if ((getMapping() != null) && getMapping().isTransformationMapping()) {
            return getMapping().getFields();
        } else {
            if(isUsingOuterJoinForMultitableInheritance()) {
                return getDescriptor().getAllFields();
            } else {
                return super.getFields();
            }
        }
    }

    /**
     * INTERNAL:
     * Transform the object-level value into a database-level value
     */
    public Object getFieldValue(Object objectValue) {
        DatabaseMapping mapping = getMapping();
        Object fieldValue = objectValue;
        if ((mapping != null) && (mapping.isDirectToFieldMapping())) {
            // CR#3623207, check for IN Vector here not in mapping.
            if (objectValue instanceof Vector) {
                // This can actually be a vector for IN within expressions... however it would be better for expressions to handle this.
                Vector values = (Vector)objectValue;
                Vector fieldValues = new Vector(values.size());
                for (int index = 0; index < values.size(); index++) {
                    fieldValues.addElement(getFieldValue(values.get(index)));
                }
                fieldValue = fieldValues;
            } else {
                fieldValue = ((AbstractDirectMapping)mapping).getFieldValue(objectValue, getSession());
            }
        }

        return fieldValue;
    }

    public DatabaseMapping getMapping() {
        if (!hasMapping) {
            return null;
        }

        if (mapping == null) {
            mapping = super.getMapping();
            if (mapping == null) {
                hasMapping = false;
            }
        }
        return mapping;
    }

    public DatabaseMapping getMappingFromQueryKey() {
        QueryKey queryKey = getQueryKeyOrNull();
        if ((queryKey == null) || (!(queryKey instanceof DirectQueryKey))) {
            throw QueryException.cannotConformExpression();
        }
        mapping = queryKey.getDescriptor().getObjectBuilder().getMappingForField(((DirectQueryKey)queryKey).getField());
        if (mapping == null) {
            throw QueryException.cannotConformExpression();
        }
        return mapping;
    }

    public String getName() {
        return name;
    }

    /**
     * INTERNAL:
     */
    public Vector getOwnedTables() {
        if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
            return null;
        }

        return super.getOwnedTables();
    }

    public QueryKey getQueryKeyOrNull() {
        if (!hasQueryKey) {
            return null;
        }

        // Oct 19, 2000 JED
        // Added try/catch. This was throwing a NPE in the following case
        // expresssionBuilder.get("firstName").get("bob")
        //moved by Gordon Yorke to cover validate and normalize
        if (getContainingDescriptor() == null) {
            throw QueryException.invalidQueryKeyInExpression(getName());
        }
        if (queryKey == null) {
            queryKey = getContainingDescriptor().getQueryKeyNamed(getName());
            if (queryKey == null) {
                hasQueryKey = false;
            }
        }
        return queryKey;

    }

    /**
     * INTERNAL:
     * Alias the database field for our current environment
     */
    protected void initializeAliasedField() {
        DatabaseField tempField = (DatabaseField)getField().clone();
        DatabaseTable aliasedTable = getAliasedTable();

        //  Put in a special check here so that if the aliasing does nothing we don't cache the
        // result because it's invalid. This saves us from caching premature data if e.g. debugging
        // causes us to print too early"
        //	if (aliasedTable.equals(getField().getTable())) {
        //		return;
        //	} else {
        aliasedField = tempField;
        aliasedField.setTable(aliasedTable);
        //	}
    }

    /**
     * INTERNAL:
     */
    public boolean isAttribute() {
        if (getSession() == null) {// We can't tell, so say no
            return false;
        }

        try {
            QueryKey queryKey = getQueryKeyOrNull();
            if (queryKey != null) {
                return queryKey.isDirectQueryKey();
            }

            DatabaseMapping mapping = getMapping();
            if (mapping != null) {
                if (mapping.isVariableOneToOneMapping()) {
                    throw QueryException.cannotQueryAcrossAVariableOneToOneMapping(mapping, mapping.getDescriptor());
                } else {
                    return mapping.isDirectToFieldMapping();
                }
            }
        } catch (QueryException e) {
            throw e;//re-throw the query exception arisen from the query on varibale 1:1 mapping
        }
        return false;
    }

    public boolean isQueryKeyExpression() {
        return true;
    }

    /*
     * INTERNAL:
     * If this query key respresents a foreign reference answer the
     * base expression -> foreign reference join criteria.
     */
    public Expression mappingCriteria() {
        Expression selectionCriteria;

        // First look for a query key, then a mapping
        if (getQueryKeyOrNull() == null) {
            if ((getMapping() == null) || (!getMapping().isForeignReferenceMapping())) {
                return null;
            } else {
                // The join criteria is now twisted by the mappings.
                selectionCriteria = ((ForeignReferenceMapping)getMapping()).getJoinCriteria(this);
            }
        } else {
            if (!getQueryKeyOrNull().isForeignReferenceQueryKey()) {
                return null;
            } else {
                selectionCriteria = ((ForeignReferenceQueryKey)getQueryKeyOrNull()).getJoinCriteria();
                selectionCriteria = getBaseExpression().twist(selectionCriteria, this);
            }
        }

        if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
            selectionCriteria = selectionCriteria.convertToUseOuterJoin();
        }

        return selectionCriteria;
    }

    /**
     * INTERNAL:
     * Normalize the expression into a printable structure.
     * Any joins must be added to form a new root.
     */
    public Expression normalize(ExpressionNormalizer normalizer) {
        return normalize(normalizer, null);
    }

    /**
     * INTERNAL:
     * For CR#2456 if this is part of an objExp.equal(objExp), do not need to add
     * additional expressions to normalizer both times, and the foreign key join
     * replaces the equal expression.
     */
    public Expression normalize(ExpressionNormalizer normalizer, Vector foreignKeyJoinPointer) {
        if (hasBeenNormalized()) {
            return this;
        }
        super.normalize(normalizer);

        setHasBeenNormalized(true);
        if ((getMapping() != null) && getMapping().isDirectToXMLTypeMapping()) {
            normalizer.getStatement().setRequiresAliases(true);
        }

        // Check if any joins need to be added.
        if (isAttribute()) {
            return this;
        }

        // If the mapping is 'ref' or 'structure', no join needed.
        if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
            normalizer.getStatement().setRequiresAliases(true);
            return this;
        }

        // Compute if a distinct is required during normalization.
        if (shouldQueryToManyRelationship() && (!normalizer.getStatement().isDistinctComputed()) && (!normalizer.getStatement().isAggregateSelect())) {
            normalizer.getStatement().useDistinct();
        }

        // Turn off DISTINCT if nestedTableMapping is used (not supported by Oracle 8.1.5).
        if ((getMapping() != null) && getMapping().isNestedTableMapping()) {
            // There are two types of nested tables, one used by clients, one used by mappings, do nothing in the mapping case.
            if (!shouldQueryToManyRelationship()) {
                return this;
            }
            normalizer.getStatement().dontUseDistinct();
        }

        Expression mappingExpression = mappingCriteria();
        if (mappingExpression != null) {
            mappingExpression = mappingExpression.normalize(normalizer);
        }
        if (mappingExpression != null) {
            // If the join was an outer join we must not add the join criteria to the where clause,
            // if the platform prints the join in the from clause.
            if (shouldUseOuterJoin() && (getSession().getPlatform().isInformixOuterJoin())) {
                normalizer.getStatement().getOuterJoinExpressions().addElement(this);
                normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression);
                normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria()));
                return this;
            } else if ((shouldUseOuterJoin() || isUsingOuterJoinForMultitableInheritance()) && (!getSession().getPlatform().shouldPrintOuterJoinInWhereClause())) {
                if(shouldUseOuterJoin()) {
                    normalizer.getStatement().getOuterJoinExpressions().addElement(this);
                    normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression);
                    normalizer.getStatement().getOuterJoinedAdditionalJoinCriteria().addElement(additionalExpressionCriteriaMap());
                    normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(null);
                    return this;
                } else {
                    if (isUsingOuterJoinForMultitableInheritance()) {
                        normalizer.getStatement().getOuterJoinExpressions().addElement(null);
                        normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(null);
                        normalizer.getStatement().getOuterJoinedAdditionalJoinCriteria().addElement(additionalExpressionCriteriaMap());
                        normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(getMapping().getReferenceDescriptor());
                        // fall through to the main case
                    }
                }
            }
            
            // This must be added even if outer. Actually it should be converted to use a right outer join, but that gets complex
            // so we do not support this current which is a limitation in some cases.
            if (foreignKeyJoinPointer != null) {
                // If this expression is right side of an objExp.equal(objExp), one
                // need not add additionalExpressionCriteria twice.
                // Also the join will replace the original objExp.equal(objExp).
                // For CR#2456.
                foreignKeyJoinPointer.add(mappingExpression);
            } else {
                normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria()));
            }
        }

        // For bug 2900974 special code for DirectCollectionMappings moved to printSQL.
        return this;
    }

    /**
     * INTERNAL:
     * Print SQL onto the stream, using the ExpressionPrinter for context
     */
    public void printSQL(ExpressionSQLPrinter printer) {
        if (isAttribute()) {
            printer.printField(getAliasedField());
        }

        // If the mapping is a direct collection then this falls into a gray area.
        // It must be treated as an attribute at this moment for it has a direct field.
        // However it is not an attribute in the sense that it also represents a foreign
        // reference and a mapping criteria has been added.
        // For bug 2900974 these are now handled as non-attributes during normalize but
        // as attributes when printing SQL.
        //
        if ((getMapping() != null) && getMapping().isDirectCollectionMapping()) {
            DirectCollectionMapping directCollectionMapping = (DirectCollectionMapping)getMapping();

            // The aliased table comes for free as it was a required part of the join criteria.
            TableExpression table = (TableExpression)getTable(directCollectionMapping.getReferenceTable());
            DatabaseTable aliasedTable = table.aliasForTable(table.getTable());
            DatabaseField aliasedField = (DatabaseField)directCollectionMapping.getDirectField().clone();
            aliasedField.setTable(aliasedTable);
            printer.printField(aliasedField);
        }
    }

    /**
     * INTERNAL:
     * Print java for project class generation
     */
    public void printJava(ExpressionJavaPrinter printer) {
        getBaseExpression().printJava(printer);
        if (!shouldUseOuterJoin()) {
            if (!shouldQueryToManyRelationship()) {
                printer.printString(".get(");
            } else {
                printer.printString(".anyOf(");
            }
        } else {
            if (!shouldQueryToManyRelationship()) {
                printer.printString(".getAllowingNull(");
            } else {
                printer.printString(".anyOfAllowingNone(");
            }
        }
        printer.printString("\"" + getName() + "\")");
    }

    /**
     * INTERNAL:
     * This expression is built on a different base than the one we want. Rebuild it and
     * return the root of the new tree
     */
    public Expression rebuildOn(Expression newBase) {
        Expression newLocalBase = getBaseExpression().rebuildOn(newBase);
        QueryKeyExpression result = null;

        // For bug 3096634 rebuild outer joins correctly from the start.
        if (shouldUseOuterJoin) {
            result = (QueryKeyExpression)newLocalBase.getAllowingNull(getName());
        } else {
            result = (QueryKeyExpression)newLocalBase.get(getName());
        }
        if (shouldQueryToManyRelationship) {
            result.doQueryToManyRelationship();
        }
        return result;
    }

    /**
     * INTERNAL:
     * A special version of rebuildOn where the newBase need not be a new
     * ExpressionBuilder but any expression.
     * 

* For nested joined attributes, the joined attribute query must have * its joined attributes rebuilt relative to it. */ public Expression rebuildOn(Expression oldBase, Expression newBase) { if (this == oldBase) { return newBase; } Expression newLocalBase = ((QueryKeyExpression)getBaseExpression()).rebuildOn(oldBase, newBase); QueryKeyExpression result = null; // For bug 3096634 rebuild outer joins correctly from the start. if (shouldUseOuterJoin) { result = (QueryKeyExpression)newLocalBase.getAllowingNull(getName()); } else { result = (QueryKeyExpression)newLocalBase.get(getName()); } if (shouldQueryToManyRelationship) { result.doQueryToManyRelationship(); } result.setSelectIfOrderedBy(selectIfOrderedBy()); return result; } /** * Reset cached information here so that we can be sure we're accurate. */ protected void resetCache() { hasMapping = true; mapping = null; hasQueryKey = true; queryKey = null; } public boolean shouldQueryToManyRelationship() { return shouldQueryToManyRelationship; } /** * INTERNAL: * Rebuild myself against the base, with the values of parameters supplied by the context * expression. This is used for transforming a standalone expression (e.g. the join criteria of a mapping) * into part of some larger expression. You normally would not call this directly, instead calling twist * See the comment there for more details" */ public Expression twistedForBaseAndContext(Expression newBase, Expression context) { Expression twistedBase = getBaseExpression().twistedForBaseAndContext(newBase, context); QueryKeyExpression result = (QueryKeyExpression)twistedBase.get(getName()); if (shouldUseOuterJoin) { result.doUseOuterJoin(); } if (shouldQueryToManyRelationship) { result.doQueryToManyRelationship(); } return result; } /** * Do any required validation for this node. Throw an exception if it's incorrect. */ public void validateNode() { if ((getQueryKeyOrNull() == null) && (getMapping() == null)) { throw QueryException.invalidQueryKeyInExpression(getName()); } QueryKey queryKey = getQueryKeyOrNull(); DatabaseMapping mapping = getMapping(); Object theOneThatsNotNull = null; if (queryKey != null) { theOneThatsNotNull = queryKey; } if (mapping != null) { theOneThatsNotNull = mapping; } boolean qkIsToMany = false; if (queryKey != null) { qkIsToMany = queryKey.isManyToManyQueryKey() || queryKey.isOneToManyQueryKey(); } if (mapping != null) { // Bug 2847621 - Add Aggregate Collection to the list of valid items for outer join. if (shouldUseOuterJoin && (!(mapping.isOneToOneMapping() || mapping.isOneToManyMapping() || mapping.isManyToManyMapping() || mapping.isAggregateCollectionMapping() || mapping.isDirectCollectionMapping()))) { throw QueryException.outerJoinIsOnlyValidForOneToOneMappings(getMapping()); } qkIsToMany = mapping.isCollectionMapping(); } if ((!shouldQueryToManyRelationship()) && qkIsToMany && (!mapping.isNestedTableMapping())) { throw QueryException.invalidUseOfToManyQueryKeyInExpression(theOneThatsNotNull); } if (shouldQueryToManyRelationship() && !qkIsToMany) { throw QueryException.invalidUseOfAnyOfInExpression(theOneThatsNotNull); } } /** * INTERNAL: * Return the value for in memory comparison. * This is only valid for valueable expressions. */ public Object valueFromObject(Object object, AbstractSession session, AbstractRecord translationRow, InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean isObjectUnregistered) { // The expression may be across a relationship, in which case it must be traversed. if ((getBuilder() != getBaseExpression()) && getBaseExpression().isQueryKeyExpression()) { object = getBaseExpression().valueFromObject(object, session, translationRow, valueHolderPolicy, isObjectUnregistered); // toDo: Null means the join filters out the row, returning null is not correct if an inner join, // outer/inner joins need to be fixed to filter correctly. if (object == null) { return null; } // If from an anyof the object will be a collection of values, // A new vector must union the object values and the values extracted from it. if (object instanceof Vector) { Vector comparisonVector = new Vector(((Vector)object).size() + 2); for (Enumeration valuesToIterate = (Enumeration)((Vector)object).elements(); valuesToIterate.hasMoreElements();) { Object vectorObject = (Object)valuesToIterate.nextElement(); if (vectorObject == null) { comparisonVector.addElement(vectorObject); } else { Object valueOrValues = valuesFromCollection(vectorObject, session, valueHolderPolicy, isObjectUnregistered); // If a collection of values were extracted union them. if (valueOrValues instanceof Vector) { for (Enumeration nestedValuesToIterate = (Enumeration)((Vector)valueOrValues).elements(); nestedValuesToIterate.hasMoreElements();) { comparisonVector.addElement(nestedValuesToIterate.nextElement()); } } else { comparisonVector.addElement(valueOrValues); } } } return comparisonVector; } } return valuesFromCollection(object, session, valueHolderPolicy, isObjectUnregistered); } /** * INTERNAL * This method iterates through a collection and gets the values from the objects to conform in an in-memory query. * Creation date: (1/19/01 1:18:27 PM) */ public Object valuesFromCollection(Object object, AbstractSession session, InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean isObjectUnregistered) { // in case the mapping is null - this can happen if a query key is being used // In this case, check for the query key and find it's mapping. boolean readMappingFromQueryKey = false; if (getMapping() == null) { getMappingFromQueryKey(); readMappingFromQueryKey = true; } // For bug 2780817 get the mapping directly from the object. In EJB 2.0 // inheritance, each child must override mappings defined in an abstract // class with its own. DatabaseMapping mapping = this.mapping; if (mapping.getDescriptor().hasInheritance() && (mapping.getDescriptor().getJavaClass() != object.getClass())) { mapping = session.getDescriptor(object.getClass()).getObjectBuilder().getMappingForAttributeName(getName()); } //fetch group support if (mapping.getDescriptor().hasFetchGroupManager()) { FetchGroupManager fetchGroupMgr = mapping.getDescriptor().getFetchGroupManager(); if (fetchGroupMgr.isPartialObject(object) && (!fetchGroupMgr.isAttributeFetched(object, mapping.getAttributeName()))) { //the conforming attribute is not fetched, simply throw exception throw QueryException.cannotConformUnfetchedAttribute(mapping.getAttributeName()); } } if (mapping.isForeignReferenceMapping()) { //CR 3677 integration of a ValueHolderPolicy Object valueFromMapping = mapping.getAttributeValueFromObject(object); if (!((ForeignReferenceMapping)mapping).getIndirectionPolicy().objectIsInstantiated(valueFromMapping)) { if (!valueHolderPolicy.shouldTriggerIndirection()) { //If the client wishes us to trigger the indirection then we should do so, //Other wise throw the exception throw QueryException.mustInstantiateValueholders();// you should instantiate the valueholder for this to work } // maybe we should throw this exception from the start, to save time } Object valueToIterate = mapping.getRealAttributeValueFromObject(object, session); UnitOfWorkImpl uow = isObjectUnregistered ? (UnitOfWorkImpl)session : null; // First check that object in fact is unregistered. // toDo: ?? Why is this commented out? Why are we supporting the unregistered thing at all? // Does not seem to be any public API for this, nor every used internally? //if (isObjectUnregistered) { // isObjectUnregistered = !uow.getCloneMapping().containsKey(object); //} if (mapping.isCollectionMapping() && (valueToIterate != null)) { // For bug 2766379 must use the correct version of vectorFor to // unwrap the result same time. valueToIterate = mapping.getContainerPolicy().vectorFor(valueToIterate, session); // toDo: If the value is empty, need to support correct inner/outer join filtering symantics. // For CR 2612601, try to partially replace the result with already // registered objects. if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) { Vector objectValues = (Vector)valueToIterate; for (int i = 0; i < objectValues.size(); i++) { Object original = objectValues.elementAt(i); Object clone = uow.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(original); if (clone != null) { objectValues.setElementAt(clone, i); } } } // For CR 2612601, conforming without registering, a query could be // bob.get("address").get("city").equal("Ottawa"); where the address // has been registered and modified in the UOW, but bob has not. Thus // even though bob does not point to the modified address now, it will // as soon as it is registered, so should point to it here. } else if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) { Object clone = uow.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(valueToIterate); if (clone != null) { valueToIterate = clone; } } return valueToIterate; } else if (mapping.isDirectToFieldMapping()) { return ((AbstractDirectMapping)mapping).valueFromObject(object, mapping.getField(), session); } else if (mapping.isAggregateMapping()) { Object aggregateValue = ((AggregateMapping)mapping).getAttributeValueFromObject(object); ; // Bug 3995468 - if this query key is to a mapping in an aggregate object, get the object from actual mapping rather than the aggregate mapping while (readMappingFromQueryKey && mapping.isAggregateObjectMapping() && !((AggregateObjectMapping)mapping).getReferenceClass().equals(queryKey.getDescriptor().getJavaClass())) { mapping = mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(((DirectQueryKey)queryKey).getField()); aggregateValue = mapping.getRealAttributeValueFromObject(aggregateValue, session); } return aggregateValue; } else { throw QueryException.cannotConformExpression(); } } /** * INTERNAL: * Used to print a debug form of the expression tree. */ public void writeDescriptionOn(BufferedWriter writer) throws IOException { writer.write(getName()); writer.write(tableAliasesDescription()); } /** * INTERNAL: * Indicates that RelationExpression.normalize method shouldn't attempt * optimize normalization by not normalizing this. */ public boolean isNormalizationRequired() { return shouldQueryToManyRelationship() || // For bug 2718460, some QueryKeyExpressions have a query key but no mapping. // An example is the "back-ref" query key for batch reads. Must not // attempt the optimization for these. getMapping() == null || // For bug 5234283: WRONG =* SQL FOR LEFT JOIN ON DERBY AND DB2 PLATFORMS // Caused by QueryKeyExpression never been normilized. // The condition should be kept in sync with condtions in normalize method // that trigger adding to normalizer.getStatement().getOuterJoin... ((shouldUseOuterJoin() || isUsingOuterJoinForMultitableInheritance()) && !getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) || (shouldUseOuterJoin() && getSession().getPlatform().isInformixOuterJoin()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy