Package org.datanucleus.store.mapped.expression

Source Code of org.datanucleus.store.mapped.expression.ExpressionHelper

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

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

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

Contributors:
2003 Andy Jefferson - coding standards
2005 Andy Jefferson - added handling for left outer join of related fields when in fetch group
2006 Andy Jefferson - added support for primary join table and select of owner object
    ...
**********************************************************************/
package org.datanucleus.store.mapped.expression;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.Relation;
import org.datanucleus.store.mapped.DatastoreClass;
import org.datanucleus.store.mapped.DatastoreContainerObject;
import org.datanucleus.store.mapped.DatastoreElementContainer;
import org.datanucleus.store.mapped.DatastoreIdentifier;
import org.datanucleus.store.mapped.IdentifierType;
import org.datanucleus.store.mapped.MappedStoreManager;
import org.datanucleus.store.mapped.StatementMappingIndex;
import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
import org.datanucleus.store.mapped.mapping.ReferenceMapping;

/**
* Helper class for doing tasks relating to expressions and handling mappings in query statements.
*/
public class ExpressionHelper
{
    /**
     * Convenience method to select the specified mapping in the specified query.
     * The supplied stmtMapping has its column positions updated to the position in this
     * query.
     * @param stmtMapping The statement mapping to select
     * @param qs The query
     * @param tableIdentifier Identifier for the table in which to select the mapping (if known)
     * @param clr ClassLoader resolver
     */
    public static void selectMapping(StatementMappingIndex stmtMapping, QueryExpression qs,
            DatastoreIdentifier tableIdentifier, ClassLoaderResolver clr)
    {
        if (stmtMapping == null)
        {
            return;
        }
        JavaTypeMapping m = stmtMapping.getMapping();
        if (m == null)
        {
            return;
        }

        AbstractMemberMetaData fmd = m.getMemberMetaData();
        if (m.getNumberOfDatastoreFields() > 0)
        {
            int[] columnNumbersByField =
                (tableIdentifier != null) ? qs.select(tableIdentifier, m, true) : qs.select(m, true);
            stmtMapping.setColumnPositions(columnNumbersByField);
        }
        else
        {
            int relationType = fmd.getRelationType(clr);
            if (relationType == Relation.ONE_TO_ONE_BI && fmd.getMappedBy() != null)
            {
                // 1-1 bi with "mapped-by" at this side (hence no column(s)).
                // This field is not stored, but instead a foreign is set in the source table which stores
                // a reference to this (target table). A FK is set in the source table referring to the
                // target table. Do a LEFT OUTER JOIN to the related (source) table(s) to pick up the
                // identifier value of this.
                /*
                 * For example :-
                 * TABLE A (TARGET)               TABLE B (SOURCE)
                 * ID                             ID  A_ID (FK)
                 * --                             --  ----
                 * 18                             21  18
                 *
                 * Class A                        Class B
                 * {                              {
                 *    B b;                            A a;
                 * }                              }
                 */
                int[] colNums = null;
                MappedStoreManager storeMgr = qs.getStoreManager();
                JavaTypeMapping[] sourceMappings = null;
                DatastoreClass[] sourceTables = null;
                if (m instanceof ReferenceMapping)
                {
                    // Reference field (with "n" implementations)
                    JavaTypeMapping[] refMappings = ((ReferenceMapping)m).getJavaTypeMapping();
                    sourceTables = new DatastoreClass[refMappings.length];
                    sourceMappings = new JavaTypeMapping[refMappings.length];
                    for (int j=0;j<refMappings.length;j++)
                    {
                        sourceTables[j] = storeMgr.getDatastoreClass(refMappings[j].getType(), clr);
                        sourceMappings[j] = sourceTables[j].getMemberMapping(fmd.getMappedBy());
                    }
                }
                else
                {
                    // PC field
                    sourceTables = new DatastoreClass[1];
                    sourceMappings = new JavaTypeMapping[1];
                    sourceTables[0] = storeMgr.getDatastoreClass(fmd.getTypeName(), clr);
                    sourceMappings[0] = sourceTables[0].getMemberMapping(fmd.getMappedBy());
                }

                for (int j=0;j<sourceMappings.length;j++)
                {
                    // Do a LEFT OUTER JOIN for this sourceMapping back to the target id column(s)

                    // TODO Move this hardcoded table name out into the calling class so it controls the names of all table aliases
                    DatastoreIdentifier sourceTableIdentifier =
                        storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.TABLE,
                            "SOURCECLASS" + fmd.getAbsoluteFieldNumber() + "_" + j);
                    LogicSetExpression sourceTableExpr = qs.newTableExpression(sourceTables[j], sourceTableIdentifier, true)[0];

                    // Left outer join from target ID to the mapped-by field on the source class
                    ScalarExpression sourceExpr = sourceMappings[j].newScalarExpression(qs, sourceTableExpr);
                    ScalarExpression targetExpr;
                    if (tableIdentifier != null)
                    {
                        LogicSetExpression targetTableExpr;
                        if (qs.getTableExpression(tableIdentifier) == null)
                        {
                            targetTableExpr = qs.newTableExpression(m.getDatastoreContainer(), tableIdentifier);
                        }
                        else
                        {
                            targetTableExpr = qs.getTableExpression(tableIdentifier);
                        }
                        targetExpr = m.getDatastoreContainer().getIDMapping().newScalarExpression(qs, targetTableExpr);
                    }
                    else
                    {
                        targetExpr = m.getDatastoreContainer().getIDMapping().newScalarExpression(qs,
                            qs.getMainTableExpression());
                    }
                    qs.leftOuterJoin(sourceExpr, targetExpr, sourceTableExpr, true, true);

                    // Select the Id column(s) of the source class (via the Left Outer Join)
                    int[] columnNumbersByField = qs.select(sourceTableIdentifier, sourceTables[j].getIDMapping(), true);

                    // Copy these column numbers into our overall column numbers set
                    if (sourceMappings.length == 1)
                    {
                        // We only have one source so just reference these
                        colNums = columnNumbersByField;
                    }
                    else if (colNums != null)
                    {
                        // Append to the end of where we have got to
                        int[] tmpColNums = colNums;
                        colNums = new int[tmpColNums.length + columnNumbersByField.length];
                        for (int k=0;k<tmpColNums.length;k++)
                        {
                            colNums[k] = tmpColNums[k];
                        }
                        for (int k=0;k<columnNumbersByField.length;k++)
                        {
                            colNums[tmpColNums.length+k] = columnNumbersByField[k];
                        }
                        tmpColNums = null;
                    }
                    else
                    {
                        // Add to the start of our column numbers
                        colNums = new int[columnNumbersByField.length];
                        for (int k=0;k<columnNumbersByField.length;k++)
                        {
                            colNums[k] = columnNumbersByField[k];
                        }
                    }
                }

                stmtMapping.setColumnPositions(colNums);
            }
            else if (relationType == Relation.MANY_TO_ONE_BI)
            {
                AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
                // TODO Cater for more than 1 related field
                if (fmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null)
                {
                    // 1-N bidirectional join table relation
                    // Do a LEFT OUTER JOIN to the join table to pick up the value.
                    MappedStoreManager storeMgr = qs.getStoreManager();
                    DatastoreContainerObject joinTable = storeMgr.getDatastoreContainerObject(relatedMmds[0]);
                    DatastoreElementContainer collTable = (DatastoreElementContainer)joinTable;
                    JavaTypeMapping referenceMapping = collTable.getElementMapping();
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();

                    DatastoreContainerObject mainTable = qs.getMainTableExpression().getMainTable();
                    if (!mainTable.equals(joinTable))
                    {
                        // Statement selects the element table and the owner column should be selected
                        // Join across to the join table, and select the owner mapping of the join table

                        // TODO Move this hardcoded table name out into the calling class so it controls the names of all table aliases
                        DatastoreIdentifier joinTableIdentifier =
                            storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.TABLE,
                                "JOINTABLE" + fmd.getAbsoluteFieldNumber());
                        LogicSetExpression table_expr_sub = qs.newTableExpression(joinTable, joinTableIdentifier, true)[0];

                        // Left outer join from our Id to the mapped-by field on the other class
                        ScalarExpression subExpr = referenceMapping.newScalarExpression(qs, table_expr_sub);
                        ScalarExpression schExpr = null;
                        if (tableIdentifier != null)
                        {
                            LogicSetExpression targetTableExpr;
                            if (qs.getTableExpression(tableIdentifier) == null)
                            {
                                targetTableExpr = qs.newTableExpression(m.getDatastoreContainer(), tableIdentifier);
                            }
                            else
                            {
                                targetTableExpr = qs.getTableExpression(tableIdentifier);
                            }
                            schExpr = m.getDatastoreContainer().getIDMapping().newScalarExpression(qs, targetTableExpr);
                        }
                        else
                        {
                            schExpr = m.getDatastoreContainer().getIDMapping().newScalarExpression(qs, qs.getMainTableExpression());
                        }
                        qs.leftOuterJoin(subExpr, schExpr, table_expr_sub, true, true);

                        // Select the Id column(s) of the other class (via the Left Outer Join)
                        int[] columnNumbersByField = qs.select(joinTableIdentifier, selectMapping, true);
                        stmtMapping.setColumnPositions(columnNumbersByField);
                    }
                    else
                    {
                        // The statement selects the join table, and joins to the element, and the owner column should be selected
                        // Select the owner mapping of the join table directly (no join needed)
                        int[] columnNumbersByField = qs.select(selectMapping, true);
                        stmtMapping.setColumnPositions(columnNumbersByField);
                    }
                }
            }
        }
    }
}
TOP

Related Classes of org.datanucleus.store.mapped.expression.ExpressionHelper

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