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

org.datanucleus.store.rdbms.scostore.BackingStoreHelper Maven / Gradle / Ivy

There is a newer version: 6.0.7
Show newest version
/**********************************************************************
Copyright (c) 2009 Andy Jefferson 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:
    ...
**********************************************************************/
package org.datanucleus.store.rdbms.scostore;

import java.lang.reflect.Modifier;
import java.sql.PreparedStatement;
import java.util.Collection;
import java.util.Iterator;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ExecutionContext;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.DiscriminatorStrategy;
import org.datanucleus.state.ObjectProvider;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.fieldmanager.ParameterSetter;
import org.datanucleus.store.rdbms.mapping.MappingHelper;
import org.datanucleus.store.rdbms.mapping.java.EmbeddedElementPCMapping;
import org.datanucleus.store.rdbms.mapping.java.EmbeddedKeyPCMapping;
import org.datanucleus.store.rdbms.mapping.java.EmbeddedValuePCMapping;
import org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping;
import org.datanucleus.store.rdbms.mapping.java.ReferenceMapping;
import org.datanucleus.store.rdbms.query.StatementClassMapping;
import org.datanucleus.store.rdbms.query.StatementMappingIndex;
import org.datanucleus.store.rdbms.table.JoinTable;

/**
 * Series of helper methods for use with RDBMS backing stores.
 */
public class BackingStoreHelper
{
    private BackingStoreHelper(){}

    /**
     * Convenience method to return the owner ObjectProvider for a backing store. If the supplied ObjectProvider is embedded then finds its owner until it finds the
     * owner that is not embedded.
     * @param op Input ObjectProvider
     * @return The owner ObjectProvider
     */
    public static ObjectProvider getOwnerObjectProviderForBackingStore(ObjectProvider op)
    {
        ObjectProvider ownerOP = op;
        while (ownerOP.isEmbedded())
        {
            // Embedded object, so get the owner object it is embedded in
            ObjectProvider[] ownerOPs = op.getExecutionContext().getOwnersForEmbeddedObjectProvider(ownerOP);
            if (ownerOPs != null && ownerOPs.length == 1)
            {
                ownerOP = ownerOPs[0];
            }
            else if (ownerOPs == null || ownerOPs.length == 0)
            {
                return null;
            }
            else
            {
                // Multiple owners so take first one
                ownerOP = ownerOPs[0];
            }
        }
        return ownerOP;
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the value from the owner.
     * @param op ObjectProvider
     * @param ec execution context
     * @param ps The PreparedStatement
     * @param jdbcPosition Position in JDBC statement to populate
     * @param bcs Base container backing store
     * @return The next position in the JDBC statement
     */
    public static int populateOwnerInStatement(ObjectProvider op, ExecutionContext ec, PreparedStatement ps, int jdbcPosition, BaseContainerStore bcs)
    {
        // Find the real owner in case the provide object is embedded
        boolean embedded = false;
        ObjectProvider ownerOP = getOwnerObjectProviderForBackingStore(op);
        if (ownerOP != op)
        {
            embedded = true;
        }

        if (!bcs.getStoreManager().insertValuesOnInsert(bcs.getOwnerMapping().getDatastoreMapping(0)))
        {
            // Don't try to insert any mappings with insert parameter that isnt ? (e.g Oracle)
            return jdbcPosition;
        }

        if (bcs.getOwnerMemberMetaData() != null && !embedded)
        {
            bcs.getOwnerMapping().setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, bcs.getOwnerMapping()), ownerOP.getObject(),
                ownerOP, bcs.getOwnerMemberMetaData().getAbsoluteFieldNumber());
        }
        else
        {
            // Either we have no member info, or we are setting the owner when the provided owner is embedded, so are navigating back to the real owner
            bcs.getOwnerMapping().setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, bcs.getOwnerMapping()), ownerOP.getObject());
        }
        return jdbcPosition + bcs.getOwnerMapping().getNumberOfDatastoreMappings();
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the value for the distinguisher
     * value.
     * @param ec execution context
     * @param ps The PreparedStatement
     * @param jdbcPosition Position in JDBC statement to populate
     * @param ecs store
     * @return The next position in the JDBC statement
     */
    public static int populateRelationDiscriminatorInStatement(ExecutionContext ec, PreparedStatement ps, int jdbcPosition, ElementContainerStore ecs)
    {
        ecs.getRelationDiscriminatorMapping().setObject(ec, ps, 
            MappingHelper.getMappingIndices(jdbcPosition, ecs.getRelationDiscriminatorMapping()), ecs.getRelationDiscriminatorValue());
        return jdbcPosition + ecs.getRelationDiscriminatorMapping().getNumberOfDatastoreMappings();
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the value for the order index.
     * @param ec execution context
     * @param ps The PreparedStatement
     * @param idx The order value
     * @param jdbcPosition Position in JDBC statement to populate
     * @param orderMapping The order mapping
     * @return The next position in the JDBC statement
     */
    public static int populateOrderInStatement(ExecutionContext ec, PreparedStatement ps, int idx, int jdbcPosition,
            JavaTypeMapping orderMapping)
    {
        orderMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, orderMapping), Integer.valueOf(idx));
        return jdbcPosition + orderMapping.getNumberOfDatastoreMappings();
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the value for the element.
     * Not used with embedded PC elements.
     * @param ec execution context
     * @param ps The PreparedStatement
     * @param element The element
     * @param jdbcPosition Position in JDBC statement to populate
     * @param elementMapping mapping for the element
     * @return The next position in the JDBC statement
     */
    public static int populateElementInStatement(ExecutionContext ec, PreparedStatement ps, Object element, 
            int jdbcPosition, JavaTypeMapping elementMapping)
    {
        if (!elementMapping.getStoreManager().insertValuesOnInsert(elementMapping.getDatastoreMapping(0)))
        {
            // Don't try to insert any mappings with insert parameter that isn't ? (e.g Oracle)
            return jdbcPosition;
        }
        elementMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, elementMapping), element);
        return jdbcPosition + elementMapping.getNumberOfDatastoreMappings();
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the value for the element in a WHERE clause.
     * Like the above method except handles reference mappings where you want have some implementations as "IS NULL"
     * in the SQL, and just want to set the actual implementation FK for the element.
     * Not used with embedded PC elements.
     * @param ec execution context
     * @param ps The PreparedStatement
     * @param element The element
     * @param jdbcPosition Position in JDBC statement to populate
     * @param elementMapping mapping for the element
     * @return The next position in the JDBC statement
     */
    public static int populateElementForWhereClauseInStatement(ExecutionContext ec, PreparedStatement ps, Object element, int jdbcPosition, JavaTypeMapping elementMapping)
    {
        if (elementMapping.getStoreManager().insertValuesOnInsert(elementMapping.getDatastoreMapping(0)))
        {
            if (elementMapping instanceof ReferenceMapping && elementMapping.getNumberOfDatastoreMappings() > 1)
            {
                ReferenceMapping elemRefMapping = (ReferenceMapping)elementMapping;
                JavaTypeMapping[] elemFkMappings = elemRefMapping.getJavaTypeMapping();
                int[] positions = null;
                for (int i=0;i subclasses = storeMgr.getSubClassesForClass(info.getClassName(), true, clr);
            if (subclasses != null && subclasses.size() > 0)
            {
                Iterator iter = subclasses.iterator();
                while (iter.hasNext())
                {
                    String subclass = iter.next();
                    Class subcls = clr.classForName(subclass);
                    if (!Modifier.isAbstract(subcls.getModifiers()))
                    {
                        AbstractClassMetaData subclassCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(subclass, clr);
                        Object discVal = subclassCmd.getDiscriminatorValue();
                        if (strategy != DiscriminatorStrategy.NONE)
                        {
                            discrimMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, discrimMapping), discVal);
                            jdbcPosition += discrimMapping.getNumberOfDatastoreMappings();
                        }
                    }
                }
            }
        }
        return jdbcPosition;
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the field values from
     * the embedded element starting at the specified jdbc position.
     * @param op ObjectProvider of the owning container
     * @param element The embedded element
     * @param ps The PreparedStatement
     * @param jdbcPosition JDBC position in the statement to start at
     * @param ownerFieldMetaData The meta data for the owner field
     * @param elementMapping mapping for the element
     * @param emd Metadata for the element class
     * @param bcs Container store
     * @return The next JDBC position
     */
    public static int populateEmbeddedElementFieldsInStatement(ObjectProvider op, Object element, PreparedStatement ps,
            int jdbcPosition, AbstractMemberMetaData ownerFieldMetaData, JavaTypeMapping elementMapping,
            AbstractClassMetaData emd, BaseContainerStore bcs)
    {
        EmbeddedElementPCMapping embeddedMapping = (EmbeddedElementPCMapping) elementMapping;
        StatementClassMapping mappingDefinition = new StatementClassMapping();
        int[] elementFieldNumbers = new int[embeddedMapping.getNumberOfJavaTypeMappings()];
        for (int i = 0; i < embeddedMapping.getNumberOfJavaTypeMappings(); i++)
        {
            JavaTypeMapping fieldMapping = embeddedMapping.getJavaTypeMapping(i);
            int absFieldNum = emd.getAbsolutePositionOfMember(fieldMapping.getMemberMetaData().getName());
            elementFieldNumbers[i] = absFieldNum;
            StatementMappingIndex stmtMapping = new StatementMappingIndex(fieldMapping);
            int[] jdbcParamPositions = new int[fieldMapping.getNumberOfDatastoreMappings()];
            for (int j = 0; j < fieldMapping.getNumberOfDatastoreMappings(); j++)
            {
                jdbcParamPositions[j] = jdbcPosition++;
            }
            stmtMapping.addParameterOccurrence(jdbcParamPositions);
            mappingDefinition.addMappingForMember(absFieldNum, stmtMapping);
        }

        ObjectProvider elementOP = bcs.getObjectProviderForEmbeddedPCObject(op, element, ownerFieldMetaData, ObjectProvider.EMBEDDED_COLLECTION_ELEMENT_PC);
        elementOP.provideFields(elementFieldNumbers, new ParameterSetter(elementOP, ps, mappingDefinition));

        return jdbcPosition;
    }

    /**
     * Convenience method to populate the passed PreparedStatement with the field values from
     * the embedded map key starting at the specified jdbc position.
     * @param op ObjectProvider of the owning container
     * @param key The embedded key
     * @param ps The PreparedStatement
     * @param jdbcPosition JDBC position in the statement to start at
     * @param joinTable The Join table where the values are embedded
     * @param mapStore the map store
     * @return The next JDBC position
     */
    public static int populateEmbeddedKeyFieldsInStatement(ObjectProvider op, Object key,
            PreparedStatement ps, int jdbcPosition, JoinTable joinTable, AbstractMapStore mapStore)
    {
        AbstractClassMetaData kmd = mapStore.getKeyClassMetaData();
        EmbeddedKeyPCMapping embeddedMapping = (EmbeddedKeyPCMapping)mapStore.getKeyMapping();
        StatementClassMapping mappingDefinition = new StatementClassMapping();  
        int[] elementFieldNumbers = new int[embeddedMapping.getNumberOfJavaTypeMappings()];
        for (int i=0;i 1)
        {
            // Mapping with multiple FK, with element only matching one
            for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }

                if (containerAlias != null)
                {
                    stmt.append(containerAlias).append(".");
                }
                stmt.append(elementMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString());
                if (((ReferenceMapping)elementMapping).getJavaTypeMapping()[i].getType().equals(element.getClass().getName()))
                {
                    if (elementsSerialised)
                    {
                        stmt.append(" LIKE ");
                    }
                    else
                    {
                        stmt.append("=");
                    }
                    stmt.append(elementMapping.getDatastoreMapping(i).getUpdateInputParameter());
                }
                else
                {
                    stmt.append(" IS NULL");
                }
            }
        }
        else
        {
            for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }

                if (containerAlias != null)
                {
                    stmt.append(containerAlias).append(".");
                }
                stmt.append(elementMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString());
                if (elementsSerialised)
                {
                    stmt.append(" LIKE ");
                }
                else
                {
                    stmt.append("=");
                }
                stmt.append(elementMapping.getDatastoreMapping(i).getUpdateInputParameter());
            }
        }
    }

    /**
     * Convenience method to add a WHERE clause restricting the specified mapping.
     * Appends something like 
"[AND] MYFIELD1 = ? [AND MYFIELD2 = ?]"
* @param stmt The statement to append onto * @param mapping The mapping to restrict * @param containerAlias Any alias for the container of this mapping * @param firstWhereClause Whether this is the first WHERE clause (i.e omit the first "AND") */ public static void appendWhereClauseForMapping(StringBuilder stmt, JavaTypeMapping mapping, String containerAlias, boolean firstWhereClause) { for (int i = 0; i < mapping.getNumberOfDatastoreMappings(); i++) { if (!firstWhereClause || (firstWhereClause && i > 0)) { stmt.append(" AND "); } if (containerAlias != null) { stmt.append(containerAlias).append("."); } stmt.append(mapping.getDatastoreMapping(i).getColumn().getIdentifier().toString()); stmt.append("="); stmt.append(mapping.getDatastoreMapping(i).getInsertionInputParameter()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy