Package org.datanucleus.store.rdbms.scostore

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

/**********************************************************************
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.mapping.JavaTypeMapping;
import org.datanucleus.store.mapped.scostore.BaseElementContainerStoreSpecialization;
import org.datanucleus.store.mapped.scostore.ElementContainerStore;
import org.datanucleus.store.mapped.scostore.ElementContainerStoreSpecialization;
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.util.Localiser;

/**
* RDBMS-specific implementation of an {@link ElementContainerStoreSpecialization}.
*/
abstract class RDBMSElementContainerStoreSpecialization extends BaseElementContainerStoreSpecialization
{
    protected final RDBMSStoreManager storeMgr;

    /** Statement for getting the size of the container. */
    protected String sizeStmt;

    /** Statement for clearing the container. */
    protected String clearStmt;

    /** Statement for adding an element to the container. */
    protected String addStmt;

    /** Statement for removing an element from the container. */
    protected String removeStmt;

    /** Whether we are using a discriminator in the "size" statement. */
    protected boolean usingDiscriminatorInSizeStmt = false;

    RDBMSElementContainerStoreSpecialization(Localiser localiser, ClassLoaderResolver clr,
            RDBMSStoreManager storeMgr)
    {
        super(localiser, clr);
        this.storeMgr = storeMgr;
    }

    /**
     * Method to remove any stored statement for addition of an element.
     */
    protected void invalidateAddStmt()
    {
        addStmt = null;
    }

    /**
     * Generates the statement for adding items.
     * The EMBEDDEDFIELDX columns are only added for embedded PC elements.
     * <PRE>
     * INSERT INTO COLLTABLE (OWNERCOL,[ELEMENTCOL],[EMBEDDEDFIELD1, EMBEDDEDFIELD2,...],[ORDERCOL])
     *                       VALUES (?,?,?)
     * </PRE>
     *
     * @return The Statement for adding an item
     */
    protected String getAddStmt(ElementContainerStore ecs)
    {
        if (addStmt == null)
        {
            StringBuffer stmt = new StringBuffer();
            stmt.append("INSERT INTO ");
            stmt.append(ecs.getContainerTable().toString());
            stmt.append(" (");
            for (int i = 0; i < ecs.getOwnerMapping().getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(",");
                }
                stmt.append(ecs.getOwnerMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
            }

            for (int i = 0; i < ecs.getElementMapping().getNumberOfDatastoreMappings(); i++)
            {
                stmt.append(",");
                stmt.append(ecs.getElementMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
            }

            if (ecs.getOrderMapping() != null)
            {
                for (int i = 0; i < ecs.getOrderMapping().getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(",");
                    stmt.append(ecs.getOrderMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                }
            }
            if (ecs.getRelationDiscriminatorMapping() != null)
            {
                for (int i = 0; i < ecs.getRelationDiscriminatorMapping().getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(",");
                    stmt.append(
                        ecs.getRelationDiscriminatorMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                }
            }

            stmt.append(") VALUES (");
            for (int i = 0; i < ecs.getOwnerMapping().getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(",");
                }
                stmt.append(((RDBMSMapping) ecs.getOwnerMapping().getDatastoreMapping(i)).getInsertionInputParameter());
            }

            for (int i = 0; i < ecs.getElementMapping().getNumberOfDatastoreMappings(); i++)
            {
                stmt.append(",");
                stmt.append(((RDBMSMapping) ecs.getElementMapping().getDatastoreMapping(0)).getInsertionInputParameter());
            }

            if (ecs.getOrderMapping() != null)
            {
                for (int i = 0; i < ecs.getOrderMapping().getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(",");
                    stmt.append(((RDBMSMapping) ecs.getOrderMapping().getDatastoreMapping(0)).getInsertionInputParameter());
                }
            }
            if (ecs.getRelationDiscriminatorMapping() != null)
            {
                for (int i = 0; i < ecs.getRelationDiscriminatorMapping().getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(",");
                    stmt.append(((RDBMSMapping) ecs.getRelationDiscriminatorMapping().getDatastoreMapping(0)).getInsertionInputParameter());
                }
            }

            stmt.append(") ");

            addStmt = stmt.toString();
        }

        return addStmt;
    }

    public void executeClear(ObjectProvider ownerSM, org.datanucleus.store.mapped.scostore.ElementContainerStore ecs)
    {
        String clearStmt = getClearStmt(ecs);
        try
        {
            ExecutionContext ec = ownerSM.getExecutionContext();
            ManagedConnection mconn = storeMgr.getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, clearStmt, false);
                try
                {
                    int jdbcPosition = 1;
                    jdbcPosition = BackingStoreHelper.populateOwnerInStatement(ownerSM, ec, ps, jdbcPosition, ecs);
                    if (ecs.getRelationDiscriminatorMapping() != null)
                    {
                        BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, ecs);
                    }

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

    /**
     * Generate statement for clearing the container.
     * <PRE>
     * DELETE FROM CONTAINERTABLE WHERE OWNERCOL = ? [AND RELATION_DISCRIM=?]
     * </PRE>
     * TODO Add a discriminator restriction on this statement so we only clear ones with a
     * valid discriminator value
     *
     * @return Statement for clearing the container.
     */
    protected String getClearStmt(ElementContainerStore ecs)
    {
        if (clearStmt == null)
        {
            StringBuffer stmt = new StringBuffer();
            stmt.append("DELETE FROM ");
            stmt.append(ecs.getContainerTable().toString());
            stmt.append(" WHERE ");
            for (int i = 0; i < ecs.getOwnerMapping().getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }
                stmt.append(ecs.getOwnerMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                stmt.append(" = ");
                stmt.append(((RDBMSMapping) ecs.getOwnerMapping().getDatastoreMapping(i)).getUpdateInputParameter());
            }
            if (ecs.getRelationDiscriminatorMapping() != null)
            {
                for (int i = 0; i < ecs.getRelationDiscriminatorMapping().getNumberOfDatastoreMappings(); i++)
                {
                    stmt.append(" AND ");
                    stmt.append(
                        ecs.getRelationDiscriminatorMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                    stmt.append(" = ");
                    stmt.append(((RDBMSMapping) ecs.getRelationDiscriminatorMapping().getDatastoreMapping(i)).getUpdateInputParameter());
                }
            }
            clearStmt = stmt.toString();
        }

        return clearStmt;
    }

    public int getSize(ObjectProvider ownerSM, ElementContainerStore ecs)
    {
        int numRows;

        String sizeStmt = getSizeStmt(ecs);
        try
        {
            ExecutionContext ec = ownerSM.getExecutionContext();
            ManagedConnection mconn = storeMgr.getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                PreparedStatement ps = sqlControl.getStatementForQuery(mconn, sizeStmt);
                try
                {
                    int jdbcPosition = 1;
                    jdbcPosition = BackingStoreHelper.populateOwnerInStatement(ownerSM, ec, ps, jdbcPosition, ecs);
                    if (ecs.getElementInfo() != null && ecs.getElementInfo().length == 1)
                    {
                        // TODO Allow for multiple element types (e.g interface implementations)
                        for (int i = 0; i < ecs.getElementInfo().length; i++)
                        {
                            if (ecs.getElementInfo()[i].getDiscriminatorMapping() != null)
                            {
                                jdbcPosition =
                                    BackingStoreHelper.populateElementDiscriminatorInStatement(ec, ps,
                                        jdbcPosition, true, ecs.getElementInfo()[i], clr);
                            }
                        }
                    }
                    if (ecs.getRelationDiscriminatorMapping() != null)
                    {
                        jdbcPosition =
                            BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, ecs);
                    }

                    ResultSet rs = sqlControl.executeStatementQuery(mconn, sizeStmt, ps);
                    try
                    {
                        if (!rs.next())
                        {
                            throw new NucleusDataStoreException(localiser.msg("056007", sizeStmt));
                        }

                        numRows = rs.getInt(1);
                        JDBCUtils.logWarnings(rs);
                    }
                    finally
                    {
                        rs.close();
                    }
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            throw new NucleusDataStoreException(localiser.msg("056007", sizeStmt), e);
        }

        return numRows;
    }

    /**
     * Generate statement for getting the size of thecontainer.
     * The order part is only present when an order mapping is used.
     * The discriminator part is only present when the element has a discriminator.
     * <PRE>
     * SELECT COUNT(*) FROM TBL THIS
     * [INNER JOIN ELEM_TBL ELEM ON TBL.COL = ELEM.ID] - when no null
     * [LEFT OUTER JOIN ELEM_TBL ELEM ON TBL.COL = ELEM.ID] - when allows null
     * WHERE THIS.OWNERCOL=?
     * [AND THIS.ORDERCOL IS NOT NULL]
     * [AND (DISCRIMINATOR=? OR DISCRMINATOR=? OR DISCRIMINATOR=? [OR DISCRIMINATOR IS NULL])]
     * [AND RELATION_DISCRIM=?]
     * </PRE>
     * The discriminator part includes all subclasses of the element type.
     * If the element is in a different table to the container then an INNER JOIN will be present to
     * link the two tables, and table aliases will be present also.
     * TODO Update this to allow for getting the size when more than 1 element table.
     *
     * @return The Statement returning the size of the container.
     */
    protected String getSizeStmt(ElementContainerStore ecs)
    {
        if (sizeStmt != null && !usingDiscriminatorInSizeStmt)
        {
            // Statement exists and didnt need any discriminator when setting up the statement so just reuse it
            return sizeStmt;
        }

        boolean allowNulls = false;
        if (Boolean.TRUE.equals(ecs.getOwnerMemberMetaData().getContainer().allowNulls()))
        {
            allowNulls = true;
        }

        StringBuffer stmt = new StringBuffer();
        String containerAlias = "THIS";
        String joinedElementAlias = "ELEM";
        stmt.append("SELECT COUNT(*) FROM ");
        stmt.append(ecs.getContainerTable().toString()).append(" ").append(containerAlias);

        // Add join to element table if required (only allows for 1 element table currently)
        boolean joinedDiscrim = false;
        if (ecs.getElementInfo() != null && ecs.getElementInfo().length == 1 &&
            ecs.getElementInfo()[0].getDatastoreClass() != ecs.getContainerTable() &&
            ecs.getElementInfo()[0].getDiscriminatorMapping() != null)
        {
            // TODO Allow for more than 1 possible element table
            // Need join to the element table to restrict the discriminator
            joinedDiscrim = true;
            JavaTypeMapping elemIdMapping = ecs.getElementInfo()[0].getDatastoreClass().getIdMapping();
            if (allowNulls)
            {
                // User wants to allow for nulls so have to use left outer join
                stmt.append(" LEFT OUTER JOIN ");
            }
            else
            {
                // No nulls so use inner join
                stmt.append(" INNER JOIN ");
            }
            stmt.append(ecs.getElementInfo()[0].getDatastoreClass().toString()).append(" ").append(joinedElementAlias).append(" ON ");
            for (int i = 0; i < ecs.getElementMapping().getNumberOfDatastoreMappings(); i++)
            {
                if (i > 0)
                {
                    stmt.append(" AND ");
                }
                stmt.append(containerAlias).append(".")
                    .append(ecs.getElementMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier());
                stmt.append("=");
                stmt.append(joinedElementAlias).append(".")
                    .append(elemIdMapping.getDatastoreMapping(i).getDatastoreField().getIdentifier());
            }
        }

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

        if (ecs.getOrderMapping() != null)
        {
            // If an ordering is present, restrict to items where the index is not null to
            // eliminate records that are added but may not be positioned yet.
            for (int i = 0; i < ecs.getOrderMapping().getNumberOfDatastoreMappings(); i++)
            {
                stmt.append(" AND ");
                stmt.append(containerAlias).append(".")
                    .append(ecs.getOrderMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                stmt.append(">=0");
            }
        }

        if (ecs.getElementInfo() != null && ecs.getElementInfo().length == 1)
        {
            // TODO Support more than one element table
            // Add a discriminator filter for collections with an element discriminator
            StringBuffer discrStmt = new StringBuffer();
            for (int i = 0; i < ecs.getElementInfo().length; i++)
            {
                if (ecs.getElementInfo()[i].getDiscriminatorMapping() != null)
                {
                    usingDiscriminatorInSizeStmt = true;
                    if (discrStmt.length() > 0)
                    {
                        discrStmt.append(" OR ");
                    }
                    JavaTypeMapping discrimMapping = ecs.getElementInfo()[i].getDiscriminatorMapping();
                    for (int j = 0; j < discrimMapping.getNumberOfDatastoreMappings(); j++)
                    {
                        if (joinedDiscrim)
                        {
                            discrStmt.append(joinedElementAlias);
                        }
                        else
                        {
                            discrStmt.append(containerAlias);
                        }
                        discrStmt.append(".");
                        discrStmt.append(discrimMapping.getDatastoreMapping(j).getDatastoreField().getIdentifier().toString());
                        discrStmt.append("=");
                        discrStmt.append(((RDBMSMapping) discrimMapping.getDatastoreMapping(j)).getUpdateInputParameter());
                    }

                    HashSet subclasses = storeMgr.getSubClassesForClass(ecs.getElementInfo()[i].getClassName(), true, clr);
                    if (subclasses != null && subclasses.size() > 0)
                    {
                        for (int j = 0; j < subclasses.size(); j++)
                        {
                            for (int k = 0; k < discrimMapping.getNumberOfDatastoreMappings(); k++)
                            {
                                discrStmt.append(" OR ");
                                if (joinedDiscrim)
                                {
                                    discrStmt.append(joinedElementAlias);
                                }
                                else
                                {
                                    discrStmt.append(containerAlias);
                                }
                                discrStmt.append(".");
                                discrStmt.append(discrimMapping.getDatastoreMapping(k).getDatastoreField().getIdentifier().toString());
                                discrStmt.append("=");
                                discrStmt.append(((RDBMSMapping) discrimMapping.getDatastoreMapping(k)).getUpdateInputParameter());
                            }
                        }
                    }
                }
            }
            if (discrStmt.length() > 0)
            {
                stmt.append(" AND (");
                stmt.append(discrStmt);
                if (allowNulls)
                {
                    stmt.append(" OR ");
                    stmt.append(
                        ecs.getElementInfo()[0].getDiscriminatorMapping().getDatastoreMapping(0).getDatastoreField()
                            .getIdentifier().toString());
                    stmt.append(" IS NULL");
                }
                stmt.append(")");
            }
        }
        if (ecs.getRelationDiscriminatorMapping() != null)
        {
            for (int i = 0; i < ecs.getRelationDiscriminatorMapping().getNumberOfDatastoreMappings(); i++)
            {
                stmt.append(" AND ");
                stmt.append(containerAlias).append(".")
                    .append(ecs.getRelationDiscriminatorMapping().getDatastoreMapping(i).getDatastoreField().getIdentifier().toString());
                stmt.append("=");
                stmt.append(((RDBMSMapping) ecs.getRelationDiscriminatorMapping().getDatastoreMapping(i)).getUpdateInputParameter());
            }
        }

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

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

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.