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

org.firebirdsql.gds.ng.wire.AbstractFbWireStatement Maven / Gradle / Ivy

There is a newer version: 6.0.0-beta-1
Show newest version
/*
 * Firebird Open Source JDBC Driver
 *
 * Distributable under LGPL license.
 * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * LGPL License for more details.
 *
 * This file was created by members of the firebird development team.
 * All individual contributions remain the Copyright (C) of those
 * individuals.  Contributors to this file are either listed here or
 * can be obtained from a source control history command.
 *
 * All rights reserved.
 */
package org.firebirdsql.gds.ng.wire;

import org.firebirdsql.gds.impl.wire.WireProtocolConstants;
import org.firebirdsql.gds.impl.wire.XdrInputStream;
import org.firebirdsql.gds.impl.wire.XdrOutputStream;
import org.firebirdsql.gds.ng.AbstractFbStatement;
import org.firebirdsql.gds.ng.DeferredResponse;
import org.firebirdsql.gds.ng.FbTransaction;
import org.firebirdsql.gds.ng.LockCloseable;
import org.firebirdsql.gds.ng.StatementState;
import org.firebirdsql.gds.ng.fields.BlrCalculator;
import org.firebirdsql.gds.ng.fields.RowDescriptor;
import org.firebirdsql.gds.ng.fields.RowValue;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.Function;

import static java.util.Objects.requireNonNull;

/**
 * @author Mark Rotteveel
 * @since 3.0
 */
public abstract class AbstractFbWireStatement extends AbstractFbStatement implements FbWireStatement {

    private final Map blrCache = Collections.synchronizedMap(new WeakHashMap<>());
    private volatile int handle = WireProtocolConstants.INVALID_OBJECT;
    private final FbWireDatabase database;

    public AbstractFbWireStatement(FbWireDatabase database) {
        this.database = requireNonNull(database, "database");
    }

    @Override
    public final LockCloseable withLock() {
        return database.withLock();
    }

    /**
     * Gets the XdrInputStream.
     *
     * @return Instance of XdrInputStream
     * @throws SQLException
     *         If no connection is opened or when exceptions occur
     *         retrieving the InputStream
     */
    protected final XdrInputStream getXdrIn() throws SQLException {
        return getXdrStreamAccess().getXdrIn();
    }

    /**
     * Gets the XdrOutputStream.
     *
     * @return Instance of XdrOutputStream
     * @throws SQLException
     *         If no connection is opened or when exceptions occur
     *         retrieving the OutputStream
     */
    protected final XdrOutputStream getXdrOut() throws SQLException {
        return getXdrStreamAccess().getXdrOut();
    }

    private XdrStreamAccess getXdrStreamAccess() throws SQLException {
        if (database != null) {
            return database.getXdrStreamAccess();
        } else {
            throw new SQLException("Connection closed or no connection available");
        }
    }

    @Override
    public final FbWireDatabase getDatabase() {
        return database;
    }

    @Override
    public final int getHandle() {
        return handle;
    }

    protected final void setHandle(int handle) {
        this.handle = handle;
    }

    /**
     * Returns the (possibly cached) blr byte array for a {@link RowDescriptor}, or null if the parameter is null.
     *
     * @param rowDescriptor
     *         The row descriptor.
     * @return blr byte array or null when rowDescriptor is null
     * @throws SQLException
     *         When the {@link RowDescriptor} contains an unsupported field type.
     */
    protected final byte[] calculateBlr(RowDescriptor rowDescriptor) throws SQLException {
        if (rowDescriptor == null) return null;
        byte[] blr = blrCache.get(rowDescriptor);
        if (blr == null) {
            blr = getBlrCalculator().calculateBlr(rowDescriptor);
            blrCache.put(rowDescriptor, blr);
        }
        return blr;
    }

    /**
     * Returns the blr byte array for a {@link RowValue}, or null if the parameter is null.
     * 

* Contrary to {@link #calculateBlr(org.firebirdsql.gds.ng.fields.RowDescriptor)}, it is not allowed * to cache this value as it depends on the actual row value. *

* * @param rowValue * The row value. * @return blr byte array or null when rowValue is null * @throws SQLException * When the {@link RowValue} contains an unsupported field type. */ protected final byte[] calculateBlr(RowDescriptor rowDescriptor, RowValue rowValue) throws SQLException { if (rowDescriptor == null || rowValue == null) return null; return getBlrCalculator().calculateBlr(rowDescriptor, rowValue); } /** * @return The {@link BlrCalculator} instance for this statement (currently always the one from * the {@link FbWireDatabase} instance). */ protected final BlrCalculator getBlrCalculator() { return getDatabase().getBlrCalculator(); } @Override public void close() throws SQLException { try { super.close(); } finally { // TODO Preferably this should be done elsewhere and AbstractFbStatement.close() should be final try (LockCloseable ignored = withLock()) { blrCache.clear(); } } } @Override protected boolean isValidTransactionClass(Class transactionClass) { return FbWireTransaction.class.isAssignableFrom(transactionClass); } @Override public final RowDescriptor emptyRowDescriptor() { return database.emptyRowDescriptor(); } @Override public byte[] getSqlInfo(byte[] requestItems, int bufferLength) throws SQLException { try { checkStatementValid(); return getInfo(WireProtocolConstants.op_info_sql, requestItems, bufferLength); } catch (SQLException e) { exceptionListenerDispatcher.errorOccurred(e); throw e; } } protected byte[] getInfo(int operation, byte[] requestItems, int bufferLength) throws SQLException { return getDatabase().getInfo(operation, getHandle(), requestItems, bufferLength, getStatementWarningCallback()); } /** * Wraps a deferred response to produce a deferred action that can be added * using {@link FbWireDatabase#enqueueDeferredAction(DeferredAction)}, notifying the exception listener of this * statement for exceptions, and forcing the ERROR state for IO errors. * * @param deferredResponse * deferred response to wrap * @param responseMapper * Function to map a {@link Response} to the response object expected by the deferred response * @param * type of deferred response * @return deferred action */ protected final DeferredAction wrapDeferredResponse(DeferredResponse deferredResponse, Function responseMapper) { return DeferredAction.wrapDeferredResponse( deferredResponse, responseMapper, getStatementWarningCallback(), this::deferredExceptionHandler); } /** * Handler for exceptions to a deferred response. *

* If the exception is a {@code SQLException}, the exception listener dispatcher is notified. If the exception * or its cause is an {@code IOException}, the statement state is forced to {@code ERROR}. *

* * @param exception exception received in a deferred response, or thrown while receiving the deferred response */ private void deferredExceptionHandler(Exception exception) { if (exception instanceof SQLException) { exceptionListenerDispatcher.errorOccurred((SQLException) exception); } if (exception instanceof IOException || exception.getCause() instanceof IOException) { forceState(StatementState.ERROR); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy