Package org.datanucleus.store.rdbms.scostore

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

/**********************************************************************
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.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

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.JavaTypeMapping;
import org.datanucleus.store.mapped.scostore.ElementContainerStore;
import org.datanucleus.store.mapped.scostore.JoinListStoreSpecialization;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.SQLController;
import org.datanucleus.store.rdbms.fieldmanager.DynamicSchemaFieldManager;
import org.datanucleus.store.rdbms.mapping.RDBMSMapping;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;

/**
* RDBMS-specific implementation of a {@link JoinListStoreSpecialization}.
*/
public class RDBMSJoinListStoreSpecialization extends RDBMSAbstractListStoreSpecialization implements JoinListStoreSpecialization
{
    RDBMSJoinListStoreSpecialization(Localiser localiser, ClassLoaderResolver clr, RDBMSStoreManager storeMgr)
    {
        super(localiser, clr, storeMgr);
    }

    /**
     * Generate statement for removing a collection of items from the List.
     * <PRE>
     * DELETE FROM LISTTABLE
     * WHERE (OWNERCOL=? AND ELEMENTCOL=?) OR
     * (OWNERCOL=? AND ELEMENTCOL=?) OR
     * (OWNERCOL=? AND ELEMENTCOL=?)
     * </PRE>
     * @param elements Collection of elements to remove
     * @return Statement for deleting items from the List.
     */
    protected String getRemoveAllStmt(Collection elements, ElementContainerStore ecs)
    {
        if (elements == null || elements.size() == 0)
        {
            return null;
        }

        JavaTypeMapping ownerMapping = ecs.getOwnerMapping();
        DatastoreContainerObject containerTable = ecs.getContainerTable();
        boolean elementsAreSerialised = ecs.isElementsAreSerialised();
        JavaTypeMapping elementMapping = ecs.getElementMapping();
        JavaTypeMapping relationDiscriminatorMapping = ecs.getRelationDiscriminatorMapping();

        StringBuffer stmt = new StringBuffer();
        stmt.append("DELETE FROM ");
        stmt.append(containerTable.toString());
        stmt.append(" WHERE ");
        Iterator elementsIter = elements.iterator();
        boolean first = true;
        while (elementsIter.hasNext())
        {
            elementsIter.next(); // Not really used at the moment except to size the Collection
            if (first)
            {
                stmt.append("(");
            }
            else
            {
                stmt.append(" OR (");
            }
            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());
            }
            for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++)
            {
                stmt.append(" AND ");
                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());
            }

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

            stmt.append(")");
            first = false;
        }

        return stmt.toString();
    }

    public void removeAt(ObjectProvider sm, int index, int size, ElementContainerStore ecs)
    {
        internalRemoveAt(sm, index, getRemoveAtStmt(ecs), size, ecs);
    }

    public boolean removeAll(int currentListSize, int[] indices, Collection elements, ObjectProvider sm,
            ElementContainerStore ecs)
    {
        JavaTypeMapping elementMapping = ecs.getElementMapping();
        JavaTypeMapping relationDiscriminatorMapping = ecs.getRelationDiscriminatorMapping();

        // Remove the specified elements from the join table
        boolean modified = false;

        String removeAllStmt = getRemoveAllStmt(elements, ecs);
        SQLController sqlControl = storeMgr.getSQLController();
        try
        {
            ExecutionContext ec = sm.getExecutionContext();
            ManagedConnection mconn = storeMgr.getConnection(ec);
            try
            {
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, removeAllStmt, false);
                try
                {
                    int jdbcPosition = 1;
                    Iterator iter = elements.iterator();
                    while (iter.hasNext())
                    {
                        Object element = iter.next();
                        jdbcPosition = BackingStoreHelper.populateOwnerInStatement(sm, ec, ps, jdbcPosition, ecs);
                        jdbcPosition = BackingStoreHelper.populateElementInStatement(ec, ps, element, jdbcPosition, elementMapping);
                        if (relationDiscriminatorMapping != null)
                        {
                            jdbcPosition =
                                BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, ecs);
                        }
                    }

                    int[] number = sqlControl.executeStatementUpdate(mconn, removeAllStmt, ps, true);
                    if (number[0] > 0)
                    {
                        modified = true;
                    }
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            NucleusLogger.DATASTORE.error(e);
            throw new NucleusDataStoreException(localiser.msg("056012", removeAllStmt), e);
        }

        try
        {
            // Shift the remaining indices to remove the holes in ordering
            boolean batched = storeMgr.allowsBatching();

            ExecutionContext ec = sm.getExecutionContext();
            ManagedConnection mconn = storeMgr.getConnection(ec);
            try
            {
                for (int i = 0; i < currentListSize; i++)
                {
                    // Find the number of deleted indexes above this index
                    int shift = 0;
                    boolean removed = false;
                    for (int j = 0; j < indices.length; j++)
                    {
                        if (indices[j] == i)
                        {
                            removed = true;
                            break;
                        }
                        if (indices[j] < i)
                        {
                            shift++;
                        }
                    }
                    if (!removed && shift > 0)
                    {
                        internalShift(sm, mconn, batched, i, -1 * shift, (i == currentListSize - 1), ecs);
                    }
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (MappedDatastoreException e)
        {
            NucleusLogger.DATASTORE.error(e);
            throw new NucleusDataStoreException(localiser.msg("056012", removeAllStmt), e);
        }

        boolean dependent = ecs.getOwnerMemberMetaData().getCollection().isDependentElement();
        if (ecs.getOwnerMemberMetaData().isCascadeRemoveOrphans())
        {
            dependent = true;
        }
        if (dependent)
        {
            // "delete-dependent" : delete elements if the collection is marked as dependent
            // TODO What if the collection contains elements that are not in the List ? should not delete them
            sm.getExecutionContext().deleteObjects(elements.toArray());
        }

        return modified;
    }

    /**
     * Generates the statement for setting an item.
     * <PRE>
     * UPDATE LISTTABLE SET [ELEMENTCOL = ?]
     * [EMBEDDEDFIELD1=?, EMBEDDEDFIELD2=?, ...]
     * WHERE OWNERCOL = ?
     * AND INDEXCOL = ?
     * [AND DISTINGUISHER=?]
     * </PRE>
     * @return The Statement for setting an item
     */
    protected String getSetStmt(ElementContainerStore ecs)
    {
        if (setStmt == null)
        {
            JavaTypeMapping ownerMapping = ecs.getOwnerMapping();
            JavaTypeMapping orderMapping = ecs.getOrderMapping();
            DatastoreContainerObject containerTable = ecs.getContainerTable();
            JavaTypeMapping elementMapping = ecs.getElementMapping();
            JavaTypeMapping relationDiscriminatorMapping = ecs.getRelationDiscriminatorMapping();

            StringBuffer stmt = new StringBuffer();
            stmt.append("UPDATE ");
            stmt.append(containerTable.toString());
            stmt.append(" SET ");
            for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(",");
                }
                stmt.append(elementMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                stmt.append(" = ");
                stmt.append(((RDBMSMapping) elementMapping.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());
            }

            if (ecs.getOwnerMemberMetaData().getOrderMetaData() != null &&
                !ecs.getOwnerMemberMetaData().getOrderMetaData().isIndexedList())
            {
                // Ordered list, so can't easily do a set!!!
            }
            else
            {
                for (int i = 0; i < orderMapping.getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(" AND ");
                    stmt.append(orderMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                    stmt.append(" = ");
                    stmt.append(((RDBMSMapping) orderMapping.getDatastoreMapping(i)).getUpdateInputParameter());
                }
            }
            if (relationDiscriminatorMapping != null)
            {
                for (int i = 0; i < relationDiscriminatorMapping.getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(" AND ");
                    stmt.append(relationDiscriminatorMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                    stmt.append(" = ");
                    stmt.append(((RDBMSMapping) relationDiscriminatorMapping.getDatastoreMapping(i)).getUpdateInputParameter());
                }
            }
            setStmt = stmt.toString();
        }

        return setStmt;
    }

    public void set(Object element, int index, ObjectProvider sm, ElementContainerStore ecs)
    {
        // Check for dynamic schema updates prior to update
        if (storeMgr.getBooleanObjectProperty("datanucleus.rdbms.dynamicSchemaUpdates").booleanValue())
        {
            DynamicSchemaFieldManager dynamicSchemaFM = new DynamicSchemaFieldManager(storeMgr, sm);
            Collection coll = new ArrayList();
            coll.add(element);
            dynamicSchemaFM.storeObjectField(ecs.getOwnerMemberMetaData().getAbsoluteFieldNumber(), coll);
            if (dynamicSchemaFM.hasPerformedSchemaUpdates())
            {
                setStmt = null;
            }
        }

        JavaTypeMapping orderMapping = ecs.getOrderMapping();
        JavaTypeMapping elementMapping = ecs.getElementMapping();
        JavaTypeMapping relationDiscriminatorMapping = ecs.getRelationDiscriminatorMapping();

        String setStmt = getSetStmt(ecs);
        try
        {
            ExecutionContext ec = sm.getExecutionContext();
            ManagedConnection mconn = ecs.getStoreManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, setStmt, false);
                try
                {
                    int jdbcPosition = 1;
                    jdbcPosition =
                        BackingStoreHelper.populateElementInStatement(ec, ps, element, jdbcPosition, elementMapping);
                    jdbcPosition = BackingStoreHelper.populateOwnerInStatement(sm, ec, ps, jdbcPosition, ecs);
                    if (ecs.getOwnerMemberMetaData().getOrderMetaData() != null &&
                        !ecs.getOwnerMemberMetaData().getOrderMetaData().isIndexedList())
                    {
                        // Ordered list, so can't easily do a set!!!
                        NucleusLogger.PERSISTENCE.warn("Calling List.addElement at a position for an ordered list is a stupid thing to do; the ordering is set my the ordering specification. Use an indexed list to do this correctly");
                    }
                    else
                    {
                        jdbcPosition =
                            BackingStoreHelper.populateOrderInStatement(ec, ps, index, jdbcPosition, orderMapping);
                    }
                    if (relationDiscriminatorMapping != null)
                    {
                        jdbcPosition =
                            BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, ecs);
                    }

                    sqlControl.executeStatementUpdate(mconn, setStmt, ps, true);
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            throw new NucleusDataStoreException(localiser.msg("056015", setStmt), e);
        }
    }

    public boolean internalAdd(ObjectProvider sm, ElementContainerStore ecs, int start, boolean atEnd,
            Collection c, int currentListSize, int shift)
    {
        // Check for dynamic schema updates prior to addition
        if (storeMgr.getBooleanObjectProperty("datanucleus.rdbms.dynamicSchemaUpdates").booleanValue())
        {
            DynamicSchemaFieldManager dynamicSchemaFM = new DynamicSchemaFieldManager(storeMgr, sm);
            dynamicSchemaFM.storeObjectField(ecs.getOwnerMemberMetaData().getAbsoluteFieldNumber(), c);
            if (dynamicSchemaFM.hasPerformedSchemaUpdates())
            {
                invalidateAddStmt();
            }
        }

        String addStmt = getAddStmt(ecs);
        try
        {
            ExecutionContext ec = sm.getExecutionContext();
            ManagedConnection mconn = ecs.getStoreManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                // Shift any existing elements so that we can insert the new element(s) at their position
                if (!atEnd && start != currentListSize)
                {
                    boolean batched = currentListSize - start > 0;

                    for (int i = currentListSize - 1; i >= start; i--)
                    {
                        // Shift the index for this row by "shift"
                        internalShift(sm, mconn, batched, i, shift, (i == start), ecs);
                    }
                }
                else
                {
                    start = currentListSize;
                }

                // Insert the elements at their required location
                int jdbcPosition = 1;
                boolean batched = (c.size() > 1);

                Iterator iter = c.iterator();
                while (iter.hasNext())
                {
                    Object element = iter.next();
                    PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, addStmt, batched);
                    try
                    {
                        JavaTypeMapping orderMapping = ecs.getOrderMapping();
                        JavaTypeMapping elementMapping = ecs.getElementMapping();
                        JavaTypeMapping relationDiscriminatorMapping = ecs.getRelationDiscriminatorMapping();

                        jdbcPosition = 1;
                        jdbcPosition = BackingStoreHelper.populateOwnerInStatement(sm, ec, ps, jdbcPosition, ecs);
                        jdbcPosition = BackingStoreHelper.populateElementInStatement(ec, ps, element, jdbcPosition, elementMapping);
                        if (orderMapping != null)
                        {
                            jdbcPosition = BackingStoreHelper.populateOrderInStatement(ec, ps, start, jdbcPosition, orderMapping);
                        }
                        if (relationDiscriminatorMapping != null)
                        {
                            jdbcPosition =
                                BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, ecs);
                        }
                        start++;

                        // Execute the statement
                        sqlControl.executeStatementUpdate(mconn, addStmt, ps, !iter.hasNext());
                    }
                    finally
                    {
                        sqlControl.closeStatement(mconn, ps);
                    }
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (MappedDatastoreException e)
        {
            throw new NucleusDataStoreException(localiser.msg("056009", addStmt), e);
        }
        catch (SQLException e)
        {
            throw new NucleusDataStoreException(localiser.msg("056009", addStmt), e);
        }
        return true;
    }
}
TOP

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

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.