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

org.firebirdsql.jdbc.FBCallableStatement 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.jdbc;

import org.firebirdsql.gds.impl.GDSHelper;
import org.firebirdsql.gds.ng.LockCloseable;
import org.firebirdsql.jdbc.escape.FBEscapedCallParser;
import org.firebirdsql.jdbc.field.FBField;
import org.firebirdsql.jdbc.field.TypeConversionException;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Date;
import java.sql.*;
import java.util.*;

/**
 * Implementation of {@link java.sql.CallableStatement}.
 * 
 * @author David Jencks
 * @author Roman Rokytskyy
 * @author Steven Jardine
 * @author Mark Rotteveel
 */
public class FBCallableStatement extends FBPreparedStatement implements CallableStatement, FirebirdCallableStatement {

    static final String SET_BY_STRING_NOT_SUPPORTED = "Setting parameters by name is not supported";
    static final String NATIVE_CALL_COMMAND = "EXECUTE PROCEDURE ";
    static final String NATIVE_SELECT_COMMAND = "SELECT * FROM ";

    private ResultSet singletonRs;

    protected boolean selectableProcedure;

    protected FBProcedureCall procedureCall;

    protected FBCallableStatement(GDSHelper c, String sql, int rsType,
            int rsConcurrency, int rsHoldability, 
            StoredProcedureMetaData storedProcMetaData,
            FBObjectListener.StatementListener statementListener, 
            FBObjectListener.BlobListener blobListener) 
    throws SQLException {
        super(c, rsType, rsConcurrency, rsHoldability, statementListener, blobListener);

        FBEscapedCallParser parser = new FBEscapedCallParser();

        // here statement is parsed twice, once in c.nativeSQL(...)
        // and second time in parser.parseCall(...)... not nice, maybe
        // in the future should be fixed by calling FBEscapedParser for
        // each parameter in FBEscapedCallParser class
        // TODO Might be unnecessary now FBEscapedParser processes nested escapes
        procedureCall = parser.parseCall(nativeSQL(sql));

        if (storedProcMetaData.canGetSelectableInformation()) {
            setSelectabilityAutomatically(storedProcMetaData);
        }
    }

    @Override
    void close(boolean ignoreAlreadyClosed) throws SQLException {
        batchList = null;
        super.close(ignoreAlreadyClosed);
    }

    @Override
    public ParameterMetaData getParameterMetaData() throws SQLException {
        try (LockCloseable ignored = withLock()) {
            checkValidity();
            // TODO See http://tracker.firebirdsql.org/browse/JDBC-352
            notifyStatementStarted(false);
            prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()));
            return new FBParameterMetaData(fbStatement.getParameterDescriptor(), connection);
        }
    }

    private List batchList = new ArrayList<>();

    @Override
    public void addBatch() throws SQLException {
        try (LockCloseable ignored = withLock()) {
            checkValidity();
            procedureCall.checkParameters();
            batchList.add((FBProcedureCall) procedureCall.clone());
        }
    }

    @Override
    public void clearBatch() throws SQLException {
        try (LockCloseable ignored = withLock()) {
            checkValidity();
            // TODO Find open streams and close them?
            batchList.clear();
        }
    }

    @Override
    protected List executeBatchInternal() throws SQLException {
        try (LockCloseable ignored = withLock()) {
            checkValidity();
            List results = new ArrayList<>(batchList.size());
            notifyStatementStarted();
            try {
                prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()));
                for (FBProcedureCall fbProcedureCall : batchList) {
                    procedureCall = fbProcedureCall;
                    results.add(executeSingleForBatch());
                }
                notifyStatementCompleted();
                return results;
            } catch (SQLException e) {
                BatchUpdateException batchUpdateException = createBatchUpdateException(e, results);
                notifyStatementCompleted(false, batchUpdateException);
                throw batchUpdateException;
            } catch (RuntimeException e) {
                notifyStatementCompleted(false, e);
                throw e;
            } finally {
                clearBatch();
            }
        }
    }

    private long executeSingleForBatch() throws SQLException {
        if (internalExecute(!isSelectableProcedure())) {
            throw batchStatementReturnedResultSet();
        }

        return getLargeUpdateCountMinZero();
    }

    @Override
    public void setSelectableProcedure(boolean selectableProcedure) {
        this.selectableProcedure = selectableProcedure;
    }

    @Override
    public boolean isSelectableProcedure() {
        return selectableProcedure;
    }

    /**
     * Set required types for output parameters.
     * 
     * @throws SQLException if something went wrong.
     */
    protected void setRequiredTypes() throws SQLException {
        setRequiredTypesInternal((FBResultSet) (singletonRs != null ? singletonRs : getResultSet(false)));
    }

    private void setRequiredTypesInternal(FBResultSet resultSet) throws SQLException {
        for (FBProcedureParam param : procedureCall.getOutputParams()) {
            if (param == null) continue;

            FBField field = resultSet.getField(procedureCall.mapOutParamIndexToPosition(param.getIndex()), false);
            field.setRequiredType(param.getType());
        }
    }

    /**
     * We allow multiple calls to this method without re-preparing the statement.
     * This is a workaround to the issue that the statement is actually prepared
     * only after all OUT parameters are registered.
     */
    @Override
    protected void prepareFixedStatement(String sql) throws SQLException {
        if (fbStatement != null) return;

        super.prepareFixedStatement(sql);
    }

    /**
     * {@inheritDoc}
     * 

* Since we deferred the statement preparation until all OUT params are * registered, we ensure that the statement is prepared before the meta * data for the callable statement is obtained. *

*/ @Override public ResultSetMetaData getMetaData() throws SQLException { checkValidity(); try (LockCloseable ignored = withLock()) { // TODO See http://tracker.firebirdsql.org/browse/JDBC-352 notifyStatementStarted(false); prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure())); } return super.getMetaData(); } @Override public boolean execute() throws SQLException { try (LockCloseable ignored = withLock()) { checkValidity(); procedureCall.checkParameters(); notifyStatementStarted(); try { prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure())); boolean hasResultSet = internalExecute(!isSelectableProcedure()); if (hasResultSet) { setRequiredTypes(); } else { notifyStatementCompleted(); } return hasResultSet; } catch (Exception e) { notifyStatementCompleted(true, e); throw e; } } } //This method prepares statement before execution. Rest of the processing is done by superclass. @Override public ResultSet executeQuery() throws SQLException { try (LockCloseable ignored = withLock()) { checkValidity(); procedureCall.checkParameters(); notifyStatementStarted(); try { prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure())); if (!internalExecute(!isSelectableProcedure())) { throw queryProducedNoResultSet(); } ResultSet rs = getResultSet(false); setRequiredTypesInternal((FBResultSet) rs); return rs; } catch (Exception e) { notifyStatementCompleted(true, e); throw e; } } } // This method prepares statement before execution. Rest of the processing is done by superclass. @Override public int executeUpdate() throws SQLException { try (LockCloseable ignored = withLock()) { checkValidity(); procedureCall.checkParameters(); notifyStatementStarted(); try { prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure())); /* R.Rokytskyy: JDBC CTS suite uses executeUpdate() together with output parameters, therefore we * cannot throw exception if we want to pass the test suite. * * if (internalExecute(true)) throw updateReturnedResultSet(); */ boolean hasResults = internalExecute(!isSelectableProcedure()); if (hasResults) { setRequiredTypes(); } int updateCount = getUpdateCountMinZero(); if (!isSelectableProcedure()) { notifyStatementCompleted(); } return updateCount; } catch (Exception e) { notifyStatementCompleted(true, e); throw e; } } } // Execute statement internally. This method sets cached parameters. Rest of the processing is done by superclass. @Override protected boolean internalExecute(boolean sendOutParams) throws SQLException { singletonRs = null; int counter = 0; for (FBProcedureParam param : procedureCall.getInputParams()) { if (param != null && param.isParam()) { counter++; Object value = param.getValue(); FBField field = getField(counter); if (value == null) { field.setNull(); } else if (value instanceof WrapperWithCalendar) { setField(field, (WrapperWithCalendar)value); } else if (value instanceof WrapperWithLong) { setField(field, (WrapperWithLong)value); } else { field.setObject(value); } } } final boolean hasResultSet = super.internalExecute(sendOutParams); if (hasResultSet && isSingletonResult) { // Safeguarding first row so it will work even if the result set from getResultSet is manipulated singletonRs = new FBResultSet(fbStatement.getRowDescriptor(), connection, new ArrayList<>(specialResult), null, true, false); } return hasResultSet; } @Override protected FBResultSet createSpecialResultSet(FBObjectListener.ResultSetListener resultSetListener) throws SQLException { // retrieveBlobs is false, as they were already retrieved when initializing singletonRs in internalExecute return new FBResultSet(fbStatement.getRowDescriptor(), connection, new ArrayList<>(specialResult), resultSetListener, false, false); } private void setField(FBField field, WrapperWithLong value) throws SQLException { Object obj = value.getValue(); if (obj == null) { field.setNull(); } else { long longValue = value.getLongValue(); if (obj instanceof InputStream) { field.setBinaryStream((InputStream) obj, longValue); } else if (obj instanceof Reader) { field.setCharacterStream((Reader) obj, longValue); } else { throw new TypeConversionException("Cannot convert type " + obj.getClass().getName()); } } } private void setField(FBField field, WrapperWithCalendar value) throws SQLException { Object obj = value.getValue(); if (obj == null) { field.setNull(); } else { Calendar cal = value.getCalendar(); if (obj instanceof Timestamp) field.setTimestamp((Timestamp) obj, cal); else if (obj instanceof java.sql.Date) field.setDate((java.sql.Date) obj, cal); else if (obj instanceof Time) field.setTime((Time) obj, cal); else throw new TypeConversionException("Cannot convert type " + obj.getClass().getName()); } } @Override public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException { procedureCall.registerOutParam(parameterIndex, sqlType); } /** * {@inheritDoc} *

* Implementation note: This method will behave the same as calling {@link #registerOutParameter(int, int)}. *

*/ @Override public void registerOutParameter(int parameterIndex, int sqlType, int scale) throws SQLException { registerOutParameter(parameterIndex, sqlType); } /** * {@inheritDoc} *

* Implementation note: behaves as {@link #registerOutParameter(int, int)} called with * {@link SQLType#getVendorTypeNumber()}. *

*/ @Override public void registerOutParameter(int parameterIndex, SQLType sqlType) throws SQLException { registerOutParameter(parameterIndex, sqlType.getVendorTypeNumber()); } /** * {@inheritDoc} *

* Implementation note: behaves as {@link #registerOutParameter(int, int, int)} called with * {@link SQLType#getVendorTypeNumber()}. *

*/ @Override public void registerOutParameter(int parameterIndex, SQLType sqlType, int scale) throws SQLException { registerOutParameter(parameterIndex, sqlType.getVendorTypeNumber(), scale); } /** * {@inheritDoc} *

* Implementation note: behaves as {@link #registerOutParameter(int, int, String)} called with * {@link SQLType#getVendorTypeNumber()}. *

*/ @Override public void registerOutParameter(int parameterIndex, SQLType sqlType, String typeName) throws SQLException { registerOutParameter(parameterIndex, sqlType.getVendorTypeNumber(), typeName); } @Override public boolean wasNull() throws SQLException { return getAndAssertSingletonResultSet().wasNull(); } @Override public String getString(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getString(parameterIndex); } @Override public boolean getBoolean(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getBoolean(parameterIndex); } @Override public byte getByte(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getByte(parameterIndex); } @Override public short getShort(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getShort(parameterIndex); } @Override public int getInt(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getInt(parameterIndex); } @Override public long getLong(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getLong(parameterIndex); } @Override public float getFloat(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getFloat(parameterIndex); } @Override public double getDouble(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getDouble(parameterIndex); } @Deprecated @Override public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getBigDecimal(parameterIndex, scale); } @Override public byte[] getBytes(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getBytes(parameterIndex); } @Override public java.sql.Date getDate(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getDate(parameterIndex); } @Override public Time getTime(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getTime(parameterIndex); } @Override public Timestamp getTimestamp(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getTimestamp(parameterIndex); } /** * {@inheritDoc} *

* Implementation note: the registered type is ignored, and the type derived from the actual datatype will be used. *

*/ @Override public Object getObject(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getObject(parameterIndex); } /** * {@inheritDoc} *

* Implementation note: the registered type is ignored, and the type derived from the actual datatype will be used. *

*/ @Override public Object getObject(String colName) throws SQLException { return getAndAssertSingletonResultSet().getObject(colName); } /** * {@inheritDoc} *

* Implementation note: the registered type is ignored, and the type derived from the actual datatype will be used. *

*/ @Override public Object getObject(int parameterIndex, Map> map) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getObject(parameterIndex, map); } /** * {@inheritDoc} *

* Implementation note: the registered type is ignored, and the type derived from the actual datatype will be used. *

*/ @Override public Object getObject(String colName, Map> map) throws SQLException { return getAndAssertSingletonResultSet().getObject(colName, map); } @Override public T getObject(int parameterIndex, Class type) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getObject(parameterIndex, type); } @Override public T getObject(String parameterName, Class type) throws SQLException { return getAndAssertSingletonResultSet().getObject(parameterName, type); } @Override public BigDecimal getBigDecimal(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getBigDecimal(parameterIndex); } @Override public Ref getRef(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getRef(parameterIndex); } @Override public Blob getBlob(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getBlob(parameterIndex); } @Override public Clob getClob(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getClob(parameterIndex); } @Override public Array getArray(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getArray(parameterIndex); } @Override public java.sql.Date getDate(int parameterIndex, Calendar cal) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getDate(parameterIndex, cal); } @Override public Time getTime(int parameterIndex, Calendar cal) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getTime(parameterIndex, cal); } @Override public Timestamp getTimestamp(int parameterIndex, Calendar cal) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getTimestamp(parameterIndex, cal); } @Override public URL getURL(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getURL(parameterIndex); } @Override public String getString(String colName) throws SQLException { return getAndAssertSingletonResultSet().getString(colName); } @Override public boolean getBoolean(String colName) throws SQLException { return getAndAssertSingletonResultSet().getBoolean(colName); } @Override public byte getByte(String colName) throws SQLException { return getAndAssertSingletonResultSet().getByte(colName); } @Override public short getShort(String colName) throws SQLException { return getAndAssertSingletonResultSet().getShort(colName); } @Override public int getInt(String colName) throws SQLException { return getAndAssertSingletonResultSet().getInt(colName); } @Override public long getLong(String colName) throws SQLException { return getAndAssertSingletonResultSet().getLong(colName); } @Override public float getFloat(String colName) throws SQLException { return getAndAssertSingletonResultSet().getFloat(colName); } @Override public double getDouble(String colName) throws SQLException { return getAndAssertSingletonResultSet().getDouble(colName); } @Override public byte[] getBytes(String colName) throws SQLException { return getAndAssertSingletonResultSet().getBytes(colName); } @Override public Date getDate(String colName) throws SQLException { return getAndAssertSingletonResultSet().getDate(colName); } @Override public Time getTime(String colName) throws SQLException { return getAndAssertSingletonResultSet().getTime(colName); } @Override public Timestamp getTimestamp(String colName) throws SQLException { return getAndAssertSingletonResultSet().getTimestamp(colName); } @Override public BigDecimal getBigDecimal(String colName) throws SQLException { return getAndAssertSingletonResultSet().getBigDecimal(colName); } @Override public Ref getRef(String colName) throws SQLException { return getAndAssertSingletonResultSet().getRef(colName); } @Override public Blob getBlob(String colName) throws SQLException { return getAndAssertSingletonResultSet().getBlob(colName); } @Override public Clob getClob(String colName) throws SQLException { return getAndAssertSingletonResultSet().getClob(colName); } @Override public Array getArray(String colName) throws SQLException { return getAndAssertSingletonResultSet().getArray(colName); } @Override public Date getDate(String colName, Calendar cal) throws SQLException { return getAndAssertSingletonResultSet().getDate(colName, cal); } @Override public Time getTime(String colName, Calendar cal) throws SQLException { return getAndAssertSingletonResultSet().getTime(colName, cal); } @Override public Timestamp getTimestamp(String colName, Calendar cal) throws SQLException { return getAndAssertSingletonResultSet().getTimestamp(colName, cal); } @Override public URL getURL(String colName) throws SQLException { return getAndAssertSingletonResultSet().getURL(colName); } @Override public Reader getCharacterStream(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getCharacterStream(parameterIndex); } @Override public Reader getCharacterStream(String parameterName) throws SQLException { return getAndAssertSingletonResultSet().getCharacterStream(parameterName); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #getCharacterStream(int)}. *

*/ @Override public Reader getNCharacterStream(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getNCharacterStream(parameterIndex); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #getCharacterStream(String)} . *

*/ @Override public Reader getNCharacterStream(String parameterName) throws SQLException { return getAndAssertSingletonResultSet().getNCharacterStream(parameterName); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #getString(int)}. *

*/ @Override public String getNString(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getNString(parameterIndex); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #getString(String)}. *

*/ @Override public String getNString(String parameterName) throws SQLException { return getAndAssertSingletonResultSet().getNString(parameterName); } @Override public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setAsciiStream(String parameterName, InputStream x) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBinaryStream(String parameterName, InputStream x) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBlob(String parameterName, Blob x) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBlob(String parameterName, InputStream inputStream) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setCharacterStream(String parameterName, Reader reader) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setClob(String parameterName, Clob x) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setClob(String parameterName, Reader reader, long length) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setClob(String parameterName, Reader reader) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #setCharacterStream(String, Reader, long)}. *

*/ @Override public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException { setCharacterStream(parameterName, value, length); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #setCharacterStream(String, Reader)}. *

*/ @Override public void setNCharacterStream(String parameterName, Reader value) throws SQLException { setCharacterStream(parameterName, value); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #setClob(String, Reader, long)}. *

*/ @Override public void setNClob(String parameterName, Reader reader, long length) throws SQLException { setClob(parameterName, reader, length); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #setClob(String, Reader)}. *

*/ @Override public void setNClob(String parameterName, Reader reader) throws SQLException { setClob(parameterName, reader); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #setString(String, String)}. *

*/ @Override public void setNString(String parameterName, String value) throws SQLException { setString(parameterName, value); } @Override public void registerOutParameter(String param1, int param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void registerOutParameter(String param1, int param2, int param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void registerOutParameter(String param1, int param2, String param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } /** * {@inheritDoc} *

* Implementation note: behaves as {@link #registerOutParameter(String, int)} called with * {@link SQLType#getVendorTypeNumber()}. *

*/ @Override public void registerOutParameter(String parameterName, SQLType sqlType) throws SQLException { registerOutParameter(parameterName, sqlType.getVendorTypeNumber()); } /** * {@inheritDoc} *

* Implementation note: behaves as {@link #registerOutParameter(String, int, int)} called with * {@link SQLType#getVendorTypeNumber()}. *

*/ @Override public void registerOutParameter(String parameterName, SQLType sqlType, int scale) throws SQLException { registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), scale); } /** * {@inheritDoc} *

* Implementation note: behaves as {@link #registerOutParameter(String, int, String)} called with * {@link SQLType#getVendorTypeNumber()}. *

*/ @Override public void registerOutParameter(String parameterName, SQLType sqlType, String typeName) throws SQLException { registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), typeName); } @Override public void setURL(String param1, URL param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setNull(String param1, int param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBoolean(String param1, boolean param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setByte(String param1, byte param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setShort(String param1, short param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setInt(String param1, int param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setLong(String param1, long param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setFloat(String param1, float param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setDouble(String param1, double param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBigDecimal(String param1, BigDecimal param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setString(String param1, String param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBytes(String param1, byte[] param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setDate(String param1, Date param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setTime(String param1, Time param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setTimestamp(String param1, Timestamp param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setAsciiStream(String param1, InputStream param2, int param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setBinaryStream(String param1, InputStream param2, int param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setObject(String param1, Object param2, int param3, int param4) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setObject(String param1, Object param2, int param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setObject(String param1, Object param2) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setCharacterStream(String param1, Reader param2, int param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setDate(String param1, Date param2, Calendar param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setTime(String param1, Time param2, Calendar param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setTimestamp(String param1, Timestamp param2, Calendar param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setNull(String param1, int param2, String param3) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException { // TODO Can we implement this, how? throw new FBDriverNotCapableException(); } @Override public ResultSet getGeneratedKeys() throws SQLException { throw new FBDriverNotCapableException("getGeneratedKeys is not supported on CallableStatement"); } /** * Asserts if the current statement has data to return. It checks if the * result set has a row with data. * * @param rs result set to test * @throws java.sql.SQLException when the result set has no data. */ protected void assertHasData(ResultSet rs) throws SQLException { if (rs == null) { throw new SQLException("Current statement has no data to return.", SQLStateConstants.SQL_STATE_NO_RESULT_SET); } // check if we have a row, and try to move to the first position. if (rs.getRow() == 0) { rs.next(); } else { return; } // check if we still have no row and throw an exception in this case. if (rs.getRow() == 0) { throw new SQLException("Current statement has no data to return.", SQLStateConstants.SQL_STATE_NO_RESULT_SET); } } /** * Returns the result set for the singleton row of the callable statement and asserts it has data. If this is a * selectable procedure, or there is no singleton row, it will return the normal result set. *

* This should fix the problem described in JDBC-350 * in most circumstances. *

* * @return Either the singleton result set, or the current result set as described above * @throws SQLException For database access errors */ protected ResultSet getAndAssertSingletonResultSet() throws SQLException { final ResultSet rs = !isSelectableProcedure() && singletonRs != null ? singletonRs : getResultSet(); assertHasData(rs); return rs; } @Override public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setBinaryStream(int parameterIndex, InputStream inputStream, int length) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithLong(inputStream, length)); } @Override public void setBinaryStream(int parameterIndex, InputStream inputStream, long length) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithLong(inputStream, length)); } @Override public void setBinaryStream(int parameterIndex, InputStream inputStream) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(inputStream); } @Override public void setBlob(int parameterIndex, Blob blob) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(blob); } @Override public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithLong(inputStream, length)); } @Override public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(inputStream); } @Override public void setBoolean(int parameterIndex, boolean x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setByte(int parameterIndex, byte x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setBytes(int parameterIndex, byte[] x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithLong(reader, length)); } @Override public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithLong(reader, length)); } @Override public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(reader); } @Override public void setClob(int parameterIndex, Clob x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithLong(reader, length)); } @Override public void setClob(int parameterIndex, Reader reader) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(reader); } @Override public void setDate(int parameterIndex, java.sql.Date x, Calendar cal) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithCalendar(x, cal)); } @Override public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setDouble(int parameterIndex, double x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setFloat(int parameterIndex, float x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setInt(int parameterIndex, int x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setLong(int parameterIndex, long x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(null); } @Override public void setNull(int parameterIndex, int sqlType) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(null); } @Override public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setObject(int parameterIndex, Object x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setShort(int parameterIndex, short x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setString(int parameterIndex, String x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithCalendar(x, cal)); } @Override public void setTime(int parameterIndex, Time x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } @Override public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithCalendar(x, cal)); } @Override public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { procedureCall.getInputParam(parameterIndex).setValue(x); } /** * Set the selectability of this stored procedure from RDB$PROCEDURE_TYPE. * * @throws SQLException If no selectability information is available */ private void setSelectabilityAutomatically(StoredProcedureMetaData storedProcMetaData) throws SQLException { selectableProcedure = storedProcMetaData.isSelectable(procedureCall.getName()); } /** * Helper method to identify the right result set column for an OUT parameter name. * * @param paramName * name of the OUT parameter * @deprecated use {@code getAndAssertSingletonResultSet().findColumn(paramName)} (but verify if that is the right * thing to do); method will be removed in Jaybird 6 */ @Deprecated protected int findOutParameter(String paramName) throws SQLException { return getAndAssertSingletonResultSet().findColumn(paramName); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #getClob(int)}. *

*/ @Override public NClob getNClob(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getNClob(parameterIndex); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #getClob(String)}. *

*/ @Override public NClob getNClob(String parameterName) throws SQLException { return getAndAssertSingletonResultSet().getNClob(parameterName); } @Override public RowId getRowId(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getRowId(parameterIndex); } @Override public RowId getRowId(String parameterName) throws SQLException { return getAndAssertSingletonResultSet().getRowId(parameterName); } @Override public SQLXML getSQLXML(int parameterIndex) throws SQLException { parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex); return getAndAssertSingletonResultSet().getSQLXML(parameterIndex); } @Override public SQLXML getSQLXML(String parameterName) throws SQLException { return getAndAssertSingletonResultSet().getSQLXML(parameterName); } /** * {@inheritDoc} *

* Implementation note: This method behaves exactly the same as {@link #setClob(String, Clob)}. *

*/ @Override public void setNClob(String parameterName, NClob value) throws SQLException { setClob(parameterName, value); } @Override public void setRowId(String parameterName, RowId x) throws SQLException { throw new FBDriverNotCapableException(SET_BY_STRING_NOT_SUPPORTED); } @Override public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException { throw new FBDriverNotCapableException("Type SQLXML not supported"); } private static class WrapperWithCalendar { private final Object value; private final Calendar c; private WrapperWithCalendar(Object value, Calendar c) { this.value = value; this.c = c; } private Object getValue() { return value; } private Calendar getCalendar() { return c; } } private static class WrapperWithLong { private final Object value; private final long longValue; private WrapperWithLong(Object value, long longValue) { this.value = value; this.longValue = longValue; } private Object getValue() { return value; } private long getLongValue() { return longValue; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy