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

org.datanucleus.store.rdbms.query.AbstractRDBMSQueryResult Maven / Gradle / Ivy

/**********************************************************************
Copyright (c) 2005 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.query;

import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.datanucleus.ExecutionContext;
import org.datanucleus.FetchPlan;
import org.datanucleus.exceptions.NucleusDataStoreException;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.store.query.AbstractQueryResult;
import org.datanucleus.store.query.Query;
import org.datanucleus.store.rdbms.mapping.java.EmbeddedElementPCMapping;
import org.datanucleus.store.rdbms.mapping.java.ReferenceMapping;
import org.datanucleus.store.rdbms.mapping.java.SerialisedPCMapping;
import org.datanucleus.store.rdbms.mapping.java.SerialisedReferenceMapping;
import org.datanucleus.store.rdbms.scostore.ElementContainerStore;
import org.datanucleus.store.rdbms.scostore.ElementIteratorStatement;
import org.datanucleus.store.rdbms.scostore.IteratorStatement;
import org.datanucleus.store.types.SCOUtils;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;

/**
 * Abstract representation of a QueryResult for RDBMS queries.
 * Based on the assumption that we have a JDBC ResultSet, and we are extracting the results using a ResultObjectFactory.
 */
public abstract class AbstractRDBMSQueryResult extends AbstractQueryResult
{
    private static final long serialVersionUID = 7264180157109169910L;

    /** The ResultSet containing the results. */
    protected ResultSet rs;

    /** ResultObjectFactory for converting the result set into objects. */
    protected ResultObjectFactory rof;

    protected FetchPlan fp;

    /** The members (of the candidate, if any) that are bulk loaded. */
    protected Collection bulkLoadedMmds;

    /** Map of bulk-load (candidate) field values, keyed by the "id" of the candidate object. The value is a "Map<fieldNumber, fieldValue>". */
    protected Map> bulkLoadedValueByMemberNumber;

    /** Default to closing the statement when closing the resultSet, but allow override. */
    protected boolean closeStatementWithResultSet = true;

    boolean applyRangeChecks = false;

    /**
     * Constructor of the result from a Query.
     * @param query The Query
     * @param rof The factory to retrieve results from
     * @param rs The ResultSet from the Query Statement
     * @param fp FetchPlan
     */
    public AbstractRDBMSQueryResult(Query query, ResultObjectFactory rof, ResultSet rs, FetchPlan fp)
    {
        super(query);
        this.rof = rof;
        this.rs = rs;
        this.fp = fp;

        this.applyRangeChecks = !query.processesRangeInDatastoreQuery();
    }

    public void setCloseStatementWithResultSet(boolean flag)
    {
        this.closeStatementWithResultSet = flag;
    }

    public void registerMemberBulkResultSet(IteratorStatement iterStmt, ResultSet rs)
    {
        if (bulkLoadedValueByMemberNumber == null)
        {
            bulkLoadedValueByMemberNumber = new HashMap<>();
        }
        if (bulkLoadedMmds == null)
        {
            bulkLoadedMmds = new HashSet<>();
        }
        bulkLoadedMmds.add(iterStmt.getBackingStore().getOwnerMemberMetaData());

        try
        {
            ExecutionContext ec = query.getExecutionContext();
            AbstractMemberMetaData mmd = iterStmt.getBackingStore().getOwnerMemberMetaData();
            if (mmd.hasCollection() || mmd.hasArray())
            {
                ElementIteratorStatement elemIterStmt = (ElementIteratorStatement)iterStmt;
                ElementContainerStore backingStore = (ElementContainerStore) iterStmt.getBackingStore();
                if (backingStore.isElementsAreEmbedded() || backingStore.isElementsAreSerialised())
                {
                    int param[] = new int[backingStore.getElementMapping().getNumberOfColumnMappings()];
                    for (int i = 0; i < param.length; ++i)
                    {
                        param[i] = i + 1;
                    }

                    if (backingStore.getElementMapping() instanceof SerialisedPCMapping ||
                        backingStore.getElementMapping() instanceof SerialisedReferenceMapping ||
                        backingStore.getElementMapping() instanceof EmbeddedElementPCMapping)
                    {
                        // Element = Serialised
                        while (rs.next())
                        {
                            Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                            Object element = backingStore.getElementMapping().getObject(ec, rs, param, ec.findStateManager(owner), 
                                backingStore.getOwnerMemberMetaData().getAbsoluteFieldNumber());
                            addOwnerMemberCollectionElement(mmd, owner, element);
                        }
                    }
                    else
                    {
                        // Element = Non-PC
                        while (rs.next())
                        {
                            Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                            Object element = backingStore.getElementMapping().getObject(ec, rs, param);
                            addOwnerMemberCollectionElement(mmd, owner, element);
                        }
                    }
                }
                else if (backingStore.getElementMapping() instanceof ReferenceMapping)
                {
                    // Element is Reference (interface/Object) so just use elementMapping
                    int param[] = new int[backingStore.getElementMapping().getNumberOfColumnMappings()];
                    for (int i = 0; i < param.length; ++i)
                    {
                        param[i] = i + 1;
                    }
                    while (rs.next())
                    {
                        Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                        Object element = backingStore.getElementMapping().getObject(ec, rs, param);
                        addOwnerMemberCollectionElement(mmd, owner, element);
                    }
                }
                else
                {
                    String elementType = mmd.hasCollection() ? 
                            backingStore.getOwnerMemberMetaData().getCollection().getElementType() : backingStore.getOwnerMemberMetaData().getArray().getElementType();
                    ResultObjectFactory scoROF = new PersistentClassROF<>(ec, rs, fp,
                        elemIterStmt.getElementClassMapping(), backingStore.getElementClassMetaData(), ec.getClassLoaderResolver().classForName(elementType));
                    scoROF.setIgnoreCache(query.getIgnoreCache());
                    while (rs.next())
                    {
                        Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                        Object element = scoROF.getObject();
                        addOwnerMemberCollectionElement(mmd, owner, element);
                    }
                }
            }
            else if (mmd.hasMap())
            {
                // TODO Cater for maps
            }
        }
        catch (SQLException sqle)
        {
            NucleusLogger.DATASTORE.error("Exception thrown processing bulk loaded field " + iterStmt.getBackingStore().getOwnerMemberMetaData().getFullFieldName(), sqle);
        }
        finally
        {
            // Close the ResultSet (and its Statement)
            try
            {
                Statement stmt = null;
                try
                {
                    stmt = rs.getStatement();

                    // Close the result set
                    rs.close();
                }
                catch (SQLException e)
                {
                    NucleusLogger.DATASTORE.error(Localiser.msg("052605",e));
                }
                finally
                {
                    try
                    {
                        if (stmt != null)
                        {
                            // Close the original statement
                            stmt.close();
                        }
                    }
                    catch (SQLException e)
                    {
                        // Do nothing
                    }
                }
            }
            finally
            {
                rs = null;
            }
        }
    }

    public abstract void initialise()
    throws SQLException;

    private void addOwnerMemberCollectionElement(AbstractMemberMetaData mmd, Object owner, Object element)
    {
        Object ownerId = api.getIdForObject(owner);
        Map fieldValuesForOwner = bulkLoadedValueByMemberNumber.get(ownerId);
        if (fieldValuesForOwner == null)
        {
            fieldValuesForOwner = new HashMap<>();
            bulkLoadedValueByMemberNumber.put(ownerId, fieldValuesForOwner);
        }

        if (mmd.hasCollection())
        {
            Collection coll = (Collection) fieldValuesForOwner.get(mmd.getAbsoluteFieldNumber());
            if (coll == null)
            {
                try
                {
                    Class instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), mmd.getOrderMetaData() != null);
                    coll = (Collection) instanceType.getDeclaredConstructor().newInstance();
                    fieldValuesForOwner.put(mmd.getAbsoluteFieldNumber(), coll);
                }
                catch (Exception e)
                {
                    throw new NucleusDataStoreException(e.getMessage(), e);
                }
            }
            coll.add(element);
        }
        else if (mmd.hasArray())
        {
            Object arr = fieldValuesForOwner.get(mmd.getAbsoluteFieldNumber());
            if (arr == null)
            {
                arr = Array.newInstance(mmd.getType().getComponentType(), 1);
                Array.set(arr, 0, element);
            }
            else
            {
                int currentSize = Array.getLength(arr);
                Object array = Array.newInstance(mmd.getType().getComponentType(), currentSize+1);
                for (int i=0;i