Package org.hsqldb_voltpatches

Source Code of org.hsqldb_voltpatches.SessionData

/* Copyright (c) 2001-2009, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


package org.hsqldb_voltpatches;

import java.io.InputStream;

import org.hsqldb_voltpatches.HsqlNameManager.HsqlName;
import org.hsqldb_voltpatches.lib.CountdownInputStream;
import org.hsqldb_voltpatches.lib.HashMap;
import org.hsqldb_voltpatches.lib.Iterator;
import org.hsqldb_voltpatches.lib.LongDeque;
import org.hsqldb_voltpatches.lib.LongKeyHashMap;
import org.hsqldb_voltpatches.lib.LongKeyIntValueHashMap;
import org.hsqldb_voltpatches.lib.LongKeyLongValueHashMap;
import org.hsqldb_voltpatches.lib.OrderedHashSet;
import org.hsqldb_voltpatches.lib.ReaderInputStream;
import org.hsqldb_voltpatches.navigator.RowSetNavigator;
import org.hsqldb_voltpatches.navigator.RowSetNavigatorClient;
import org.hsqldb_voltpatches.persist.DataFileCacheSession;
import org.hsqldb_voltpatches.persist.PersistentStore;
import org.hsqldb_voltpatches.persist.PersistentStoreCollectionSession;
import org.hsqldb_voltpatches.result.Result;
import org.hsqldb_voltpatches.result.ResultConstants;
import org.hsqldb_voltpatches.result.ResultLob;
import org.hsqldb_voltpatches.types.BlobData;
import org.hsqldb_voltpatches.types.ClobData;

/*
* Session semi-persistent data structures
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.9.0
*/
public class SessionData {

    private final Database           database;
    private final Session            session;
    PersistentStoreCollectionSession persistentStoreCollection;

    // large results
    LongKeyHashMap       resultMap;
    DataFileCacheSession resultCache;

    // VALUE
    Object currentValue;

    // SEQUENCE
    HashMap        sequenceMap;
    OrderedHashSet sequenceUpdateSet;

    public SessionData(Database database, Session session) {

        this.database = database;
        this.session  = session;
        persistentStoreCollection =
            new PersistentStoreCollectionSession(session);
    }

    // transitional feature
    public PersistentStore getRowStore(TableBase table) {

        if (table.store != null) {
            return table.store;
        }

        if (table.isSessionBased) {
            return persistentStoreCollection.getStore(table);
        }

        return database.persistentStoreCollection.getStore(table);
    }

    public PersistentStore getSubqueryRowStore(TableBase table) {

        PersistentStore store = persistentStoreCollection.getStore(table);

        store.removeAll();

        return store;
    }

    public PersistentStore getNewResultRowStore(TableBase table,
            boolean isCached) {

        try {
            PersistentStore store = session.database.logger.newStore(session,
                    persistentStoreCollection, table, isCached);

            return store;
        } catch (HsqlException e) {}

        throw Error.runtimeError(ErrorCode.U_S0500, "SessionData");
    }

    // result
    void setResultSetProperties(Result command, Result result) {

        /**
         * @todo - fredt - this does not work with different prepare calls
         * with the same SQL statement, but different generated column requests
         * To fix, add comment encapsulating the generated column list to SQL
         * to differentiate between the two invocations
         */
        if (command.rsConcurrency == ResultConstants.CONCUR_READ_ONLY) {
            result.setDataResultConcurrency(ResultConstants.CONCUR_READ_ONLY);
            result.setDataResultHoldability(command.rsHoldability);
        } else {
            if (result.rsConcurrency == ResultConstants.CONCUR_READ_ONLY) {
                result.setDataResultHoldability(command.rsHoldability);

                // add warning for concurrency conflict
            } else {
                result.setDataResultHoldability(
                    ResultConstants.CLOSE_CURSORS_AT_COMMIT);
            }
        }
    }

    Result getDataResultHead(Result command, Result result,
                             boolean isNetwork) {

        int fetchSize = command.getFetchSize();

        result.setResultId(session.actionTimestamp);

        if (command.rsConcurrency == ResultConstants.CONCUR_READ_ONLY) {
            result.setDataResultConcurrency(ResultConstants.CONCUR_READ_ONLY);
            result.setDataResultHoldability(command.rsHoldability);
        } else {
            if (result.rsConcurrency == ResultConstants.CONCUR_READ_ONLY) {
                result.setDataResultHoldability(command.rsHoldability);

                // add warning for concurrency conflict
            } else {
                if (session.isAutoCommit()) {
                    result.setDataResultConcurrency(
                        ResultConstants.CONCUR_READ_ONLY);
                    result.setDataResultHoldability(
                        ResultConstants.HOLD_CURSORS_OVER_COMMIT);
                } else {
                    result.setDataResultHoldability(
                        ResultConstants.CLOSE_CURSORS_AT_COMMIT);
                }
            }
        }

        result.setDataResultScrollability(command.rsScrollability);

        boolean hold = false;
        boolean copy = false;

        if (result.rsConcurrency == ResultConstants.CONCUR_UPDATABLE) {
            hold = true;
        }

        if (isNetwork) {
            if (fetchSize != 0
                    && result.getNavigator().getSize() > fetchSize) {
                copy = true;
                hold = true;
            }
        } else {
            if (!result.getNavigator().isMemory()) {
                hold = true;
            }
        }

        if (hold) {
            if (resultMap == null) {
                resultMap = new LongKeyHashMap();
            }

            resultMap.put(result.getResultId(), result);
        }

        if (copy) {
            result = Result.newDataHeadResult(session, result, 0, fetchSize);
        }

        return result;
    }

    Result getDataResultSlice(long id, int offset, int count) {

        RowSetNavigatorClient navigator = getRowSetSlice(id, offset, count);

        return Result.newDataRowsResult(navigator);
    }

    Result getDataResult(long id) {

        Result result = (Result) resultMap.get(id);

        return result;
    }

    RowSetNavigatorClient getRowSetSlice(long id, int offset, int count) {

        Result          result = (Result) resultMap.get(id);
        RowSetNavigator source = result.getNavigator();

        if (offset + count > source.getSize()) {
            count = source.getSize() - offset;
        }

        return new RowSetNavigatorClient(source, offset, count);
    }

    public void closeNavigator(long id) {

        Result result = (Result) resultMap.remove(id);

        result.getNavigator().close();
    }

    public void closeAllNavigators() {

        if (resultMap == null) {
            return;
        }

        Iterator it = resultMap.values().iterator();

        while (it.hasNext()) {
            Result result = (Result) it.next();

            result.getNavigator().close();
        }

        resultMap.clear();
    }

    public void closeAllTransactionNavigators() {

        if (resultMap == null) {
            return;
        }

        Iterator it = resultMap.values().iterator();

        while (it.hasNext()) {
            Result result = (Result) it.next();

            if (result.rsHoldability
                    == ResultConstants.CLOSE_CURSORS_AT_COMMIT) {
                result.getNavigator().close();
                it.remove();
            }
        }

        resultMap.clear();
    }

    public DataFileCacheSession getResultCache() {

        if (resultCache == null) {
            String path = database.getTempDirectoryPath();

            if (path == null) {
                return null;
            }

            try {
                resultCache =
                    new DataFileCacheSession(database,
                                             path + "/session_"
                                             + Long.toString(session.getId()));

                resultCache.open(false);
            } catch (Throwable t) {
                return null;
            }
        }

        return resultCache;
    }

    synchronized void closeResultCache() {

        if (resultCache != null) {
            try {
                resultCache.close(false);
            } catch (HsqlException e) {}

            resultCache = null;
        }
    }

    // lobs in results
    LongKeyLongValueHashMap resultLobs = new LongKeyLongValueHashMap();

    // lobs in transaction
    LongKeyIntValueHashMap lobUsageCount = new LongKeyIntValueHashMap();
    LongDeque              createdLobs   = new LongDeque();
    boolean                hasLobOps;

    // LOBs
    // if rolled back, delete created lobs and ignore all changes
    // if committed,
    // delete created lobs that have no usage count (due to constraint violation or savepoint rollback)
    // update LobManager user counts, delete lobs that have no usage
    public void updateLobUsage(boolean commit) {

        if (!hasLobOps) {
            return;
        }

        hasLobOps = false;

        if (commit) {
            for (int i = 0; i < createdLobs.size(); i++) {
                long lobID = createdLobs.get(i);
                int  delta = lobUsageCount.get(lobID, 0);

                if (delta == 1) {
                    lobUsageCount.remove(lobID);
                    createdLobs.remove(i);

                    i--;
                } else if (!session.isBatch) {
                    database.lobManager.adjustUsageCount(lobID, delta - 1);
                    lobUsageCount.remove(lobID);
                    createdLobs.remove(i);

                    i--;
                }
            }

            if (!lobUsageCount.isEmpty()) {
                Iterator it = lobUsageCount.keySet().iterator();

                while (it.hasNext()) {
                    long lobID = it.nextLong();
                    int  delta = lobUsageCount.get(lobID);

                    database.lobManager.adjustUsageCount(lobID, delta - 1);
                }

                lobUsageCount.clear();
            }

            return;
        } else {
            for (int i = 0; i < createdLobs.size(); i++) {
                long lobID = createdLobs.get(i);

                database.lobManager.deleteLob(lobID);
            }

            createdLobs.clear();
            lobUsageCount.clear();

            return;
        }
    }

    public void updateLobUsageForBatch() {

        for (int i = 0; i < createdLobs.size(); i++) {
            long lobID = createdLobs.get(i);

            database.lobManager.deleteLob(lobID);
        }

        createdLobs.clear();
    }

    public void addToCreatedLobs(long lobID) {

        hasLobOps = true;

        createdLobs.add(lobID);
    }

    public void addLobUsageCount(long lobID) {

        int count = lobUsageCount.get(lobID, 0);

        hasLobOps = true;

        lobUsageCount.put(lobID, count + 1);
    }

    public void removeUsageCount(long lobID) {

        int count = lobUsageCount.get(lobID, 0);

        hasLobOps = true;

        lobUsageCount.put(lobID, count - 1);
    }

    /**
     * allocate storage for a new LOB
     */
    public void allocateLobForResult(ResultLob result,
                                     InputStream inputStream) {

        long                 resultLobId = result.getLobID();
        CountdownInputStream countStream;

        switch (result.getSubType()) {

            case ResultLob.LobResultTypes.REQUEST_CREATE_BYTES : {
                long blobId;
                long blobLength = result.getBlockLength();

                if (inputStream == null) {
                    blobId      = resultLobId;
                    inputStream = result.getInputStream();
                } else {
                    BlobData blob = session.createBlob(blobLength);

                    blobId = blob.getId();

                    resultLobs.put(resultLobId, blobId);
                }

                countStream = new CountdownInputStream(inputStream);

                countStream.setCount(blobLength);
                database.lobManager.setBytesForNewBlob(
                    blobId, countStream, result.getBlockLength());

                break;
            }
            case ResultLob.LobResultTypes.REQUEST_CREATE_CHARS : {
                long clobId;
                long clobLength = result.getBlockLength();

                if (inputStream == null) {
                    clobId = resultLobId;

                    if (result.getReader() != null) {
                        inputStream =
                            new ReaderInputStream(result.getReader());
                    } else {
                        inputStream = result.getInputStream();
                    }
                } else {
                    ClobData clob = session.createClob(clobLength);

                    clobId = clob.getId();

                    resultLobs.put(resultLobId, clobId);
                }

                countStream = new CountdownInputStream(inputStream);

                countStream.setCount(clobLength * 2);
                database.lobManager.setCharsForNewClob(
                    clobId, countStream, result.getBlockLength());

                break;
            }
        }
    }

    public void registerLobForResult(Result result) {

        RowSetNavigator navigator = result.getNavigator();

        while (navigator.next()) {
            Object[] data = navigator.getCurrent();

            for (int i = 0; i < data.length; i++) {
                if (data[i] instanceof BlobData) {
                    BlobData blob = (BlobData) data[i];
                    long     id   = resultLobs.get(blob.getId());

                    data[i] = database.lobManager.getBlob(session, id);
                } else if (data[i] instanceof ClobData) {
                    ClobData clob = (ClobData) data[i];
                    long     id   = resultLobs.get(clob.getId());

                    data[i] = database.lobManager.getClob(session, id);
                }
            }
        }

        resultLobs.clear();
        navigator.reset();
    }

    //
    public void startRowProcessing() {

        if (sequenceMap != null) {
            sequenceMap.clear();
        }
    }

    public Object getSequenceValue(NumberSequence sequence) {

        if (sequenceMap == null) {
            sequenceMap       = new HashMap();
            sequenceUpdateSet = new OrderedHashSet();
        }

        HsqlName key   = sequence.getName();
        Object   value = sequenceMap.get(key);

        if (value == null) {
            value = sequence.getValueObject();

            sequenceMap.put(key, value);
            sequenceUpdateSet.add(sequence);
        }

        return value;
    }
}
TOP

Related Classes of org.hsqldb_voltpatches.SessionData

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.