Package org.datanucleus.store.rdbms.scostore

Source Code of org.datanucleus.store.rdbms.scostore.RDBMSAbstractCollectionStoreSpecialization

/**********************************************************************
Copyright (c) 2007 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.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusDataStoreException;
import org.datanucleus.store.ExecutionContext;
import org.datanucleus.store.ObjectProvider;
import org.datanucleus.store.connection.ManagedConnection;
import org.datanucleus.store.mapped.DatastoreContainerObject;
import org.datanucleus.store.mapped.exceptions.MappedDatastoreException;
import org.datanucleus.store.mapped.mapping.EmbeddedElementPCMapping;
import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
import org.datanucleus.store.mapped.mapping.MappingHelper;
import org.datanucleus.store.mapped.scostore.AbstractCollectionStore;
import org.datanucleus.store.mapped.scostore.AbstractCollectionStoreSpecialization;
import org.datanucleus.store.mapped.scostore.ElementContainerStore;
import org.datanucleus.store.rdbms.JDBCUtils;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.SQLController;
import org.datanucleus.store.rdbms.mapping.RDBMSMapping;
import org.datanucleus.store.rdbms.table.JoinTable;
import org.datanucleus.util.Localiser;

/**
* RDBMS-specific implementation of an {@link AbstractCollectionStoreSpecialization}.
*/
abstract class RDBMSAbstractCollectionStoreSpecialization extends RDBMSElementContainerStoreSpecialization
    implements AbstractCollectionStoreSpecialization
{
    private String containsStmt;

    RDBMSAbstractCollectionStoreSpecialization(Localiser localiser, ClassLoaderResolver clr, RDBMSStoreManager storeMgr)
    {
        super(localiser, clr, storeMgr);
    }

    /**
     * Generate statement for update the field of an embedded element.
     * <PRE>
     * UPDATE SETTABLE
     * SET EMBEDDEDFIELD1 = ?
     * WHERE OWNERCOL=?
     * AND ELEMENTCOL = ?
     * </PRE>
     *
     * @param fieldMapping The mapping for the field within the embedded object to be updated
     * @return Statement for updating an embedded element in the Set
     */
    protected String getUpdateEmbeddedElementStmt(JavaTypeMapping fieldMapping, ElementContainerStore acs)
    {
        JavaTypeMapping ownerMapping = acs.getOwnerMapping();
        DatastoreContainerObject containerTable = acs.getContainerTable();
        JavaTypeMapping elementMapping = acs.getElementMapping();

        StringBuffer stmt = new StringBuffer();
        stmt.append("UPDATE ");
        stmt.append(containerTable.toString());
        stmt.append(" SET ");
        for (int i = 0; i < fieldMapping.getNumberOfDatastoreMappings(); i++)
        {
            if (i > 0)
            {
                stmt.append(",");
            }
            stmt.append(fieldMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
            stmt.append(" = ");
            stmt.append(((RDBMSMapping) fieldMapping.getDatastoreMapping(i)).getUpdateInputParameter());
        }

        stmt.append(" WHERE ");
        for (int i = 0; i < ownerMapping.getNumberOfDatastoreMappings(); i++)
        {
            if (i > 0)
            {
                stmt.append(" AND ");
            }
            stmt.append(ownerMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
            stmt.append(" = ");
            stmt.append(((RDBMSMapping) ownerMapping.getDatastoreMapping(i)).getUpdateInputParameter());
        }

        EmbeddedElementPCMapping embeddedMapping = (EmbeddedElementPCMapping) elementMapping;
        for (int i = 0; i < embeddedMapping.getNumberOfJavaTypeMappings(); i++)
        {
            JavaTypeMapping m = embeddedMapping.getJavaTypeMapping(i);
            if (m != null)
            {
                for (int j = 0; j < m.getNumberOfDatastoreMappings(); j++)
                {
                    stmt.append(" AND ");
                    stmt.append(m.getDatastoreMapping(j).getDatastoreField().getIdentifier().toString());
                    stmt.append(" = ");
                    stmt.append(((RDBMSMapping) m.getDatastoreMapping(j)).getUpdateInputParameter());
                }
            }
        }
        return stmt.toString();
    }

    public boolean updateEmbeddedElement(ObjectProvider sm, Object element, int fieldNumber, Object value,
            JavaTypeMapping fieldMapping, ElementContainerStore ecs)
    {
        boolean modified = false;
        String stmt = getUpdateEmbeddedElementStmt(fieldMapping, ecs);
        try
        {
            ExecutionContext ec = sm.getExecutionContext();
            ManagedConnection mconn = storeMgr.getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();

            try
            {
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, stmt, false);
                try
                {
                    int jdbcPosition = 1;
                    fieldMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, fieldMapping), value);
                    jdbcPosition += fieldMapping.getNumberOfDatastoreMappings();
                    jdbcPosition = BackingStoreHelper.populateOwnerInStatement(sm, ec, ps, jdbcPosition, ecs);
                    jdbcPosition = BackingStoreHelper.populateEmbeddedElementFieldsInStatement(sm, element,
                        ps, jdbcPosition, ((JoinTable) ecs.getContainerTable()).getOwnerMemberMetaData(),
                        ecs.getElementMapping(), ecs.getEmd(), ecs);

                    sqlControl.executeStatementUpdate(mconn, stmt, ps, true);
                    modified = true;
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            e.printStackTrace();
            // TODO Update this localised message to reflect that it is the update of an embedded element
            throw new NucleusDataStoreException(localiser.msg("056009", stmt), e);
        }
        return modified;
    }

    /**
     * Generate statement for retrieving the contents of the Collection.
     * The discriminator part is only present when the element type has
     * inheritance strategy of "superclass-table" and is Inverse.
     * <PRE>
     * SELECT OWNERCOL FROM COLLECTIONTABLE
     * WHERE OWNERCOL=?
     * AND ELEMENTCOL=?
     * [AND DISCRIMINATOR=?]
     * [AND RELATION_DISCRIM=?]
     * </PRE>
     *
     * @return Statement for retrieving the contents of the Collection.
     */
    private String getContainsStmt(AbstractCollectionStore acs)
    {
        if (containsStmt == null)
        {
            JavaTypeMapping ownerMapping = acs.getOwnerMapping();
            DatastoreContainerObject containerTable = acs.getContainerTable();
            boolean elementsAreSerialised = acs.isElementsAreSerialised();
            JavaTypeMapping elementMapping = acs.getElementMapping();
            ElementContainerStore.ElementInfo[] elementInfo = acs.getElementInfo();

            StringBuffer stmt = new StringBuffer();
            String containerAlias = "THIS";
            String joinedElementAlias = "ELEM";
            stmt.append("SELECT ");
            for (int i = 0; i < ownerMapping.getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(",");
                }
                stmt.append(ownerMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
            }
            stmt.append(" FROM ");
            stmt.append(acs.getContainerTable().toString()).append(" ").append(containerAlias);

            // Add join to element table if required (only allows for 1 element table currently)
            boolean joinedDiscrim = false;
            // TODO Enable this code applying the discrim restriction to JoinTable cases
            /*if (elementInfo != null && elementInfo[0].getTable() != containerTable && elementInfo[0].getDiscriminatorMapping() != null)
        {
            // Need join to the element table to restrict the discriminator
            joinedDiscrim = true;
            JavaTypeMapping elemIdMapping = elementInfo[0].getTable().getIdMapping();
            stmt.append(" INNER JOIN ");
            stmt.append(elementInfo[0].getTable().toString()).append(" ").append(joinedElementAlias).append(" ON ");
            for (int i=0;i<elementMapping.getNumberOfDatastoreFields();i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }
                stmt.append(containerAlias).append(".").append(elementMapping.getDataStoreMapping(i).getDatastoreField().getIdentifier());
                stmt.append("=");
                stmt.append(joinedElementAlias).append(".").append(elemIdMapping.getDataStoreMapping(0).getDatastoreField().getIdentifier());
            }
        }*/

            stmt.append(" WHERE ");

            for (int i = 0; i < ownerMapping.getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }
                stmt.append(containerAlias).append(".")
                    .append(ownerMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                stmt.append(" = ");
                stmt.append(((RDBMSMapping) ownerMapping.getDatastoreMapping(i)).getUpdateInputParameter());
            }

            for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++)
            {
                // TODO Need to allow for the element datastore mapping being a BLOB field in which case this should
                // be "AND ELEMENTCOLX LIKE ?"
                stmt.append(" AND ");
                stmt.append(containerAlias).append(".")
                    .append(elementMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                if (elementsAreSerialised)
                {
                    // Can't directly compare serialised element fields
                    stmt.append(" LIKE ");
                }
                else
                {
                    stmt.append(" = ");
                }
                stmt.append(((RDBMSMapping) elementMapping.getDatastoreMapping(i)).getUpdateInputParameter());
            }

            // TODO Remove the "containerTable == " clause and make discriminator restriction part of the JoinTable statement too
            // Needs to pass TCK M-M relationship test. see contains(StateManager, Object) method also

            if (elementInfo != null && containerTable == elementInfo[0].getDatastoreClass() &&
                elementInfo[0].getDiscriminatorMapping() != null)
            {
                // Element table has discriminator so restrict to the element-type and subclasses
                stmt.append(" AND (");

                // Add WHERE for the element and each subclass type so we restrict to valid element types
                HashSet subclasses = storeMgr.getSubClassesForClass(elementInfo[0].getClassName(), true, clr);
                for (int i = 0; i < subclasses.size() + 1; i++)
                {
                    JavaTypeMapping discrimMapping = elementInfo[0].getDiscriminatorMapping();
                    for (int j = 0; j < discrimMapping.getNumberOfDatastoreMappings(); j++)
                    {
                        if (joinedDiscrim)
                        {
                            stmt.append(joinedElementAlias);
                        }
                        else
                        {
                            stmt.append(containerAlias);
                        }
                        stmt.append(".").append(discrimMapping.getDatastoreMapping(j).getDatastoreField().getIdentifier().toString());
                        stmt.append(" = ");
                        stmt.append(((RDBMSMapping) discrimMapping.getDatastoreMapping(j)).getUpdateInputParameter());

                        if (j != discrimMapping.getNumberOfDatastoreMappings() - 1 || i != subclasses.size())
                        {
                            stmt.append(" OR ");
                        }
                    }
                }
                stmt.append(")");
            }

            JavaTypeMapping relationDiscriminatorMapping = acs.getRelationDiscriminatorMapping();
            if (relationDiscriminatorMapping != null)
            {
                // Relation uses shared resource (FK, JoinTable) so restrict to this particular relation
                for (int i = 0; i < relationDiscriminatorMapping.getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(" AND ");
                    stmt.append(containerAlias).append(".")
                        .append(relationDiscriminatorMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                    stmt.append(" = ");
                    stmt.append(((RDBMSMapping) relationDiscriminatorMapping.getDatastoreMapping(i)).getUpdateInputParameter());
                }
            }

            containsStmt = stmt.toString();
        }

        return containsStmt;
    }

    public boolean contains(ObjectProvider sm, Object element, AbstractCollectionStore acs)
    {
        boolean retval;

        DatastoreContainerObject containerTable = acs.getContainerTable();
        JavaTypeMapping elementMapping = acs.getElementMapping();
        ElementContainerStore.ElementInfo[] elementInfo = acs.getElementInfo();
        String stmt = getContainsStmt(acs);
        try
        {
            ExecutionContext ec = sm.getExecutionContext();
            ManagedConnection mconn = storeMgr.getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
                try
                {
                    int jdbcPosition = 1;
                    jdbcPosition =
                        BackingStoreHelper.populateOwnerInStatement(sm, ec, ps, jdbcPosition, acs);
                    jdbcPosition =
                        BackingStoreHelper.populateElementInStatement(ec, ps, element, jdbcPosition, elementMapping);

                    // TODO Remove the containerTable == part of this so that the discrim restriction applies to JoinTable case too
                    // Needs to pass TCK M-M relation test
                    if (elementInfo != null && elementInfo[0].getDiscriminatorMapping() != null &&
                        elementInfo[0].getDatastoreClass() == containerTable)
                    {
                        jdbcPosition =
                            BackingStoreHelper.populateElementDiscriminatorInStatement(ec, ps, jdbcPosition,
                                true, elementInfo[0], clr);
                    }
                    if (acs.getRelationDiscriminatorMapping() != null)
                    {
                        jdbcPosition =
                            BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, acs);
                    }

                    ResultSet rs = sqlControl.executeStatementQuery(mconn, stmt, ps);
                    try
                    {
                        retval = rs.next();
                        JDBCUtils.logWarnings(rs);
                    }
                    finally
                    {
                        rs.close();
                    }
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            throw new NucleusDataStoreException(localiser.msg("056008", stmt), e);
        }
        return retval;
    }

    public int[] internalRemove(ObjectProvider ownerSM, ManagedConnection conn, boolean batched, Object element, boolean executeNow,
                                AbstractCollectionStore acs) throws MappedDatastoreException
    {
        ExecutionContext ec = ownerSM.getExecutionContext();
        SQLController sqlControl = storeMgr.getSQLController();
        String removeStmt = getRemoveStmt(acs);
        try
        {
            PreparedStatement ps = sqlControl.getStatementForUpdate(conn, removeStmt, batched);
            try
            {
                int jdbcPosition = 1;
                jdbcPosition =
                    BackingStoreHelper.populateOwnerInStatement(ownerSM, ec, ps, jdbcPosition, acs);
                jdbcPosition =
                    BackingStoreHelper.populateElementInStatement(ec, ps, element, jdbcPosition, acs.getElementMapping());
                if (acs.getRelationDiscriminatorMapping() != null)
                {
                    jdbcPosition =
                        BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, acs);
                }

                // Execute the statement
                return sqlControl.executeStatementUpdate(conn, removeStmt, ps, executeNow);
            }
            finally
            {
                sqlControl.closeStatement(conn, ps);
            }
        }
        catch (SQLException sqle)
        {
            throw new MappedDatastoreException("SQLException", sqle);
        }
    }

    /**
     * Generate statement for removing an element from the Collection.
     * <PRE>
     * DELETE FROM COLLTABLE WHERE OWNERCOL=? AND ELEMENTCOL = ?
     * </PRE>
     * @param ecs Element container store
     * @return Statement for deleting an item from the Collection.
     */
    protected String getRemoveStmt(ElementContainerStore ecs)
    {
        JavaTypeMapping ownerMapping = ecs.getOwnerMapping();
        DatastoreContainerObject containerTable = ecs.getContainerTable();
        boolean elementsAreSerialised = ecs.isElementsAreSerialised();
        JavaTypeMapping elementMapping = ecs.getElementMapping();

        if (removeStmt == null)
        {
            // Generate the statement
            StringBuffer stmt = new StringBuffer();
            stmt.append("DELETE FROM ");
            stmt.append(containerTable.toString());

            // Add join to element table if required (only allows for 1 element table currently)
/*            ElementContainerStore.ElementInfo[] elementInfo = ecs.getElementInfo();
            boolean joinedDiscrim = false;
            if (elementInfo != null && elementInfo[0].getDatastoreClass() != containerTable &&
                elementInfo[0].getDiscriminatorMapping() != null)
            {
                joinedDiscrim = true;
                stmt.append(" USING ");
                stmt.append(elementInfo[0].getDatastoreClass().toString());
            }*/

            stmt.append(" WHERE ");
            for (int i = 0; i < ownerMapping.getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }
                stmt.append(containerTable.toString()).append(".");
                stmt.append(ownerMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                stmt.append(" = ");
                stmt.append(((RDBMSMapping) ownerMapping.getDatastoreMapping(i)).getUpdateInputParameter());
            }
            for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++)
            {
                stmt.append(" AND ");
                stmt.append(containerTable.toString()).append(".");
                stmt.append(elementMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                if (elementsAreSerialised)
                {
                    // Can't directly compare serialised element fields
                    stmt.append(" LIKE ");
                }
                else
                {
                    stmt.append(" = ");
                }
                stmt.append(((RDBMSMapping) elementMapping.getDatastoreMapping(i)).getUpdateInputParameter());
            }

            JavaTypeMapping relationDiscriminatorMapping = ecs.getRelationDiscriminatorMapping();
            if (relationDiscriminatorMapping != null)
            {
                // Relation uses shared resource (FK, JoinTable) so restrict to this particular relation
                for (int i = 0; i < relationDiscriminatorMapping.getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(" AND ");
                    stmt.append(containerTable.toString()).append(".")
                        .append(relationDiscriminatorMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                    stmt.append(" = ");
                    stmt.append(((RDBMSMapping) relationDiscriminatorMapping.getDatastoreMapping(i)).getUpdateInputParameter());
                }
            }

            removeStmt = stmt.toString();
        }
        return removeStmt;
    }
}
TOP

Related Classes of org.datanucleus.store.rdbms.scostore.RDBMSAbstractCollectionStoreSpecialization

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.