Class AbstractFbStatement

java.lang.Object
org.firebirdsql.gds.ng.AbstractFbStatement
All Implemented Interfaces:
AutoCloseable, FbStatement, ExceptionListenable
Direct Known Subclasses:
AbstractFbWireStatement

public abstract class AbstractFbStatement extends Object implements FbStatement
Since:
3.0
Author:
Mark Rotteveel
  • Field Details

  • Constructor Details

    • AbstractFbStatement

      protected AbstractFbStatement()
  • Method Details

    • getTransactionListener

      protected final TransactionListener getTransactionListener()
      Gets the TransactionListener instance for this statement.

      This method should only be called by this object itself. Subclasses may provide their own transaction listener, but the instance returned by this method should be the same for the lifetime of this FbStatement.

      Returns:
      The transaction listener instance for this statement.
    • getStatementWarningCallback

      protected final WarningMessageCallback getStatementWarningCallback()
    • asyncFetchRows

      public void asyncFetchRows(int fetchSize) throws SQLException
      Description copied from interface: FbStatement
      Requests the server to perform an asynchronous fetch for fetch size.

      Asynchronous fetching is an optional feature. If an implementation does not support asynchronous fetching, it should return immediately and do nothing. Although this interface provides a default implementation which does nothing, implementations should override it, to throw an exception when called on a closed statement.

      For implementations which do support async fetching, this call should not do anything if one of the following is true:

      • an asynchronous fetch is already pending
      • fetchSize is 1 or the statement has a cursor name set
      • the current statement has a scrollable cursor (flag CURSOR_TYPE_SCROLLABLE set)
      • the connection property asyncFetch is false

      An asynchronous fetch can be completed explicitly by calling FbStatement.fetchRows(int), or implicitly by other network operations.

      Specified by:
      asyncFetchRows in interface FbStatement
      Parameters:
      fetchSize - number of rows to fetch (must be greater than 0)
      Throws:
      SQLException - for database access errors, when called on a closed statement, when no cursor is open or when the fetch size is not greater than 0
      See Also:
    • hasFetched

      public final boolean hasFetched()
      Description copied from interface: FbStatement
      Has at least one fetch been executed on the current cursor?
      Specified by:
      hasFetched in interface FbStatement
      Returns:
      true if at least one fetch has been executed on the current cursor, false otherwise (including if nothing has been executed, or the current statement has no cursor)
    • checkFetchSize

      protected final void checkFetchSize(int fetchSize) throws SQLException
      Validates if fetchSize is positive, otherwise throws an exception.
      Parameters:
      fetchSize - fetch size (must be positive)
      Throws:
      SQLException - if fetchSize is smaller than 1
      Since:
      6
    • close

      public void close() throws SQLException
      Description copied from interface: FbStatement
      Close and deallocate this statement.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface FbStatement
      Throws:
      SQLException
    • closeCursor

      public final void closeCursor() throws SQLException
      Description copied from interface: FbStatement
      Closes the cursor associated with this statement, leaving the statement itself allocated.

      Equivalent to calling FbStatement.closeCursor(boolean) with false.

      Specified by:
      closeCursor in interface FbStatement
      Throws:
      SQLException
    • closeCursor

      public final void closeCursor(boolean transactionEnd) throws SQLException
      Description copied from interface: FbStatement
      Closes the cursor associated with this statement, leaving the statement itself allocated.

      When this method is called in preparation of a commit, rollback or another operation which will close the cursor (see transactionEnd), then implementations may opt to not close the cursor on the server as the server closes the cursor automatically, or the statement as a whole is closed by the implementation.

      Specified by:
      closeCursor in interface FbStatement
      Parameters:
      transactionEnd - close is in response to a transaction end or another operation which will implicitly close the cursor
      Throws:
      SQLException
    • ensureClosedCursor

      public final void ensureClosedCursor(boolean transactionEnd) throws SQLException
      Description copied from interface: FbStatement
      Ensures that the statement cursor is closed. Resets a statement, so it is ready to be reused for re-execute or prepare.
      Specified by:
      ensureClosedCursor in interface FbStatement
      Parameters:
      transactionEnd - Close is in response to a transaction end
      Throws:
      SQLException - If this statement is closed or the cursor could not be closed.
    • unprepare

      public void unprepare() throws SQLException
      Description copied from interface: FbStatement
      Attempts to unprepare the currently prepared statement.

      For Firebird versions that do not support DSQL_unprepare, the implementation should attempt to close the cursor (using FbStatement.closeCursor()).

      Specified by:
      unprepare in interface FbStatement
      Throws:
      SQLException - If a database access error occurs
    • getState

      public final StatementState getState()
      Specified by:
      getState in interface FbStatement
      Returns:
      The current state of this statement
    • switchState

      protected final void switchState(StatementState newState) throws SQLException
      Sets the StatementState.
      Parameters:
      newState - New state
      Throws:
      SQLException - When the state is changed to an illegal next state
    • forceState

      protected void forceState(StatementState newState)
      Forces the statement to the specified state without throwing an exception if this is not a valid transition.

      Does nothing if current state is CLOSED.

      Parameters:
      newState - New state
      See Also:
    • getType

      public final StatementType getType()
      Specified by:
      getType in interface FbStatement
      Returns:
      The statement type
    • setType

      protected void setType(StatementType type)
      Sets the StatementType
      Parameters:
      type - New type
    • queueRowData

      protected final void queueRowData(RowValue rowData)
      Queues row data for consumption
      Parameters:
      rowData - Row data
    • setBeforeFirst

      protected final void setBeforeFirst()
      Marks the cursor position as before-first.

      All registered StatementListener instances are notified for the StatementListener.beforeFirst(FbStatement) event.

    • isBeforeFirst

      protected final boolean isBeforeFirst()
    • setAfterLast

      protected final void setAfterLast()
      Marks the cursor position as after-last.

      All registered StatementListener instances are notified for the StatementListener.afterLast(FbStatement) event.

    • isAfterLast

      protected final boolean isAfterLast()
    • reset

      protected final void reset()
      Reset statement state, equivalent to calling reset(boolean) with false.
    • resetAll

      protected final void resetAll()
      Reset statement state and clear parameter description, equivalent to calling reset(boolean) with true.
    • reset

      protected void reset(boolean resetAll)
      Resets the statement for next execution. Implementation in derived class must lock on FbStatement.withLock() and call super.reset(resetAll)
      Parameters:
      resetAll - Also reset field and parameter info
    • isPrepareAllowed

      protected boolean isPrepareAllowed(StatementState state)
      Is a call to FbStatement.prepare(String) allowed for the supplied StatementState.
      Parameters:
      state - The statement state
      Returns:
      true call to prepare is allowed
    • checkPrepareAllowed

      protected final StatementState checkPrepareAllowed() throws SQLException
      Checks if prepare is allowed, returning the current statement state.

      This method checks if the current transaction is active, and if the current statement state allows preparing a new statement.

      Returns:
      statement state
      Throws:
      SQLException - if there is no active transaction, or the current state does not allow statement prepare
      Since:
      6
    • getParameterDescriptor

      public final RowDescriptor getParameterDescriptor()
      Specified by:
      getParameterDescriptor in interface FbStatement
      Returns:
      descriptor of the parameters of this statement
    • setParameterDescriptor

      protected void setParameterDescriptor(RowDescriptor parameterDescriptor)
      Sets the parameter descriptor.
      Parameters:
      parameterDescriptor - Parameter descriptor
    • getRowDescriptor

      public final RowDescriptor getRowDescriptor()
      Specified by:
      getRowDescriptor in interface FbStatement
      Returns:
      descriptor of the row returned by this statement
    • setRowDescriptor

      protected void setRowDescriptor(RowDescriptor rowDescriptor)
      Sets the (result set) row descriptor.
      Parameters:
      rowDescriptor - Row descriptor
    • getStatementInfoRequestItems

      public byte[] getStatementInfoRequestItems()
      Returns:
      The (full) statement info request items.
      See Also:
    • getParameterDescriptionInfoRequestItems

      public byte[] getParameterDescriptionInfoRequestItems()
      Returns:
      The isc_info_sql_describe_vars info request items.
      See Also:
    • fetchScroll

      public final void fetchScroll(FetchType fetchType, int fetchSize, int position) throws SQLException
      Description copied from interface: FbStatement
      Requests this statement to fetch rows using the specified fetch type.

      The default implementation only supports FetchType.NEXT by redirecting to FbStatement.fetchRows(int) and throws an SQLFeatureNotSupported for other types.

      The caller is responsible for tracking and correcting for server-side positional state, taking into account any rows already fetched. For example, if 100 rows have been fetched with NEXT or PRIOR, and 80 rows are still in the local buffer, the server-side position is actually 80 rows ahead (or behind). The next fetch with RELATIVE will need to correct this in position, and a PRIOR after a NEXT or a NEXT after a PRIOR will need to reposition with RELATIVE or ABSOLUTE, or know how many rows to ignore from the fetched batch.

      If an asynchronous fetch is pending, the behaviour depends on the value of fetchType: if FetchType.NEXT, the fetch should be completed instead of performing a new fetch. For any other value, a SQLException should be thrown. Given FbStatement.asyncFetchRows(int) should be a no-op for scrollable cursors, this should not normally happen.

      Specified by:
      fetchScroll in interface FbStatement
      Parameters:
      fetchType - Fetch type
      fetchSize - Number of rows to fetch (must be > 0) (ignored by server for types other than FetchType.NEXT and FetchType.PRIOR)
      position - Absolute or relative position for the row to fetch (ignored by server for types other than FetchType.ABSOLUTE and FetchType.RELATIVE)
      Throws:
      SQLFeatureNotSupportedException - For types other than FetchType.NEXT if the protocol version or the implementation does not support scroll fetch
      SQLException - For database access errors, when called on a closed statement, when no cursor is open, when an async fetch is pending and fetchType is not NEXT, or for server-side error conditions
      See Also:
    • fetchScrollImpl

      protected void fetchScrollImpl(FetchType fetchType, int fetchSize, int position) throws SQLException
      Implementation of fetchScroll(FetchType, int, int).

      An implementation should not notify exceptionListenerDispatcher, as that is already handled in fetchScroll(FetchType, int, int).

      The implementation of fetchScroll(FetchType, int, int) redirects FetchType.NEXT to FbStatement.fetchRows(int). The implementation does need to handle NEXT, but only when actually implementing the other scroll direction.

      Throws:
      SQLFeatureNotSupportedException - If the protocol version or the implementation does not support scroll fetch (even for NEXT)
      SQLException - For database access errors, when called on a closed statement, when no cursor is open, or for serverside error conditions
      See Also:
    • getSqlInfo

      public final <T> T getSqlInfo(byte[] requestItems, int bufferLength, InfoProcessor<T> infoProcessor) throws SQLException
      Request statement info.
      Specified by:
      getSqlInfo in interface FbStatement
      Parameters:
      requestItems - Array of info items to request
      bufferLength - Response buffer length to use
      infoProcessor - Implementation of InfoProcessor to transform the info response
      Returns:
      Transformed info response of type T
      Throws:
      SQLException - For errors retrieving or transforming the response.
    • getCursorInfo

      public final <T> T getCursorInfo(byte[] requestItems, int bufferLength, InfoProcessor<T> infoProcessor) throws SQLException
      Description copied from interface: FbStatement
      Request cursor info.
      Specified by:
      getCursorInfo in interface FbStatement
      Parameters:
      requestItems - Array of info items to request
      bufferLength - Response buffer length to use
      infoProcessor - Implementation of InfoProcessor to transform the info response
      Returns:
      Transformed info response of type T
      Throws:
      SQLException - For errors retrieving or transforming the response
      SQLFeatureNotSupportedException - If requesting cursor info is not supported (Firebird 4.0 or earlier, or native implementation)
      See Also:
    • getCursorInfo

      public final byte[] getCursorInfo(byte[] requestItems, int bufferLength) throws SQLException
      Description copied from interface: FbStatement
      Request cursor info.
      Specified by:
      getCursorInfo in interface FbStatement
      Parameters:
      requestItems - Array of info items to request
      bufferLength - Response buffer length to use
      Returns:
      Response buffer
      Throws:
      SQLException - For errors retrieving or transforming the response
      SQLFeatureNotSupportedException - If requesting cursor info is not supported (Firebird 4.0 or earlier, or native implementation)
    • getCursorInfoImpl

      protected byte[] getCursorInfoImpl(byte[] requestItems, int bufferLength) throws SQLException
      Implementation of getCursorInfo(byte[], int).

      An implementation should not notify exceptionListenerDispatcher, as that is already handled in getCursorInfo(byte[], int).

      Throws:
      SQLException - For errors retrieving or transforming the response
      SQLFeatureNotSupportedException - If requesting cursor info is not supported (Firebird 4.0 or earlier, or native implementation)
      See Also:
    • getExecutionPlan

      public final String getExecutionPlan() throws SQLException
      Specified by:
      getExecutionPlan in interface FbStatement
      Returns:
      The execution plan of the currently prepared statement
      Throws:
      SQLException - If this statement is closed.
    • getExplainedExecutionPlan

      public final String getExplainedExecutionPlan() throws SQLException
      Specified by:
      getExplainedExecutionPlan in interface FbStatement
      Returns:
      The detailed execution plan of the currently prepared statement
      Throws:
      SQLException - If this statement is closed.
    • createExecutionPlanProcessor

      protected ExecutionPlanProcessor createExecutionPlanProcessor()
      Returns:
      New instance of ExecutionPlanProcessor (or subclass) for this statement.
    • getSqlCounts

      public SqlCountHolder getSqlCounts() throws SQLException
      Description copied from interface: FbStatement
      Retrieves the SQL counts for the last execution of this statement.

      The retrieved SQL counts are also notified to all registered StatementListeners.

      In general the FbStatement will (should) retrieve and notify listeners of the SQL counts automatically at times where it is relevant (eg after executing a statement that does not produce multiple rows, or after fetching all rows).

      Specified by:
      getSqlCounts in interface FbStatement
      Returns:
      The SQL counts of the last execution of this statement
      Throws:
      SQLException - If this statement is closed, or if this statement is in state StatementState.CURSOR_OPEN and not all rows have been fetched.
    • createSqlCountProcessor

      protected SqlCountProcessor createSqlCountProcessor()
      Returns:
      New instance of SqlCountProcessor (or subclass) for this statement.
    • free

      protected abstract void free(int option) throws SQLException
      Frees the currently allocated statement. Either close the cursor with ISCConstants.DSQL_close or drop the statement handle using ISCConstants.DSQL_drop.
      Parameters:
      option - Free option
      Throws:
      SQLException
    • validateParameters

      public final void validateParameters(RowValue parameters) throws SQLException
      Description copied from interface: FbStatement
      Validates if the number of parameters matches the expected number and types, and if all values have been set.
      Specified by:
      validateParameters in interface FbStatement
      Parameters:
      parameters - Parameter values to validate
      Throws:
      SQLException - When the number or type of parameters does not match FbStatement.getParameterDescriptor(), or when a parameter has not been set.
    • addStatementListener

      public final void addStatementListener(StatementListener statementListener)
      Description copied from interface: FbStatement
      Registers a StatementListener.
      Specified by:
      addStatementListener in interface FbStatement
      Parameters:
      statementListener - The statement listener
    • addWeakStatementListener

      public void addWeakStatementListener(StatementListener statementListener)
      Description copied from interface: FbStatement
      Adds a StatementListener instance to this database using a weak reference.

      If the listener is already strongly referenced, this call will be ignored

      Specified by:
      addWeakStatementListener in interface FbStatement
      Parameters:
      statementListener - statement listener
    • removeStatementListener

      public final void removeStatementListener(StatementListener statementListener)
      Description copied from interface: FbStatement
      Specified by:
      removeStatementListener in interface FbStatement
      Parameters:
      statementListener - The statement listener
    • addExceptionListener

      public final void addExceptionListener(ExceptionListener listener)
      Description copied from interface: ExceptionListenable
      Adds an exception listener to this object.

      Implementations use WeakReference.

      Specified by:
      addExceptionListener in interface ExceptionListenable
      Parameters:
      listener - Listener to register
    • removeExceptionListener

      public final void removeExceptionListener(ExceptionListener listener)
      Description copied from interface: ExceptionListenable
      Removes an exception listener to this object.
      Specified by:
      removeExceptionListener in interface ExceptionListenable
      Parameters:
      listener - Listener to remove
    • checkStatementValid

      protected final void checkStatementValid() throws SQLException
      Checks if this statement is not in StatementState.CLOSED, StatementState.CLOSING, StatementState.NEW or StatementState.ERROR, and throws an SQLException if it is.
      Throws:
      SQLException - when this statement is closed or in error state
    • checkStatementValid

      protected final void checkStatementValid(StatementState ignoreState) throws SQLException
      Performs the same check as checkStatementValid(), but considers ignoreState as valid.
      Parameters:
      ignoreState - the invalid state (see checkStatementValid() to ignore
      Throws:
      SQLException - when this statement is closed or in error state
    • checkStatementHasOpenCursor

      protected final void checkStatementHasOpenCursor() throws SQLException
      Checks if statement is valid with checkStatementValid() and then checks if the current statement state has an open cursor.
      Throws:
      SQLException - when this statement is closed or in error state, or has no open cursor
      Since:
      6
    • getTransaction

      public FbTransaction getTransaction()
      Specified by:
      getTransaction in interface FbStatement
      Returns:
      Transaction currently associated with this statement
    • isValidTransactionClass

      protected abstract boolean isValidTransactionClass(Class<? extends FbTransaction> transactionClass)
      Method to decide if a transaction implementation class is valid for the statement implementation.

      Eg a V10Statement will only work with an FbWireTransaction implementation.

      Parameters:
      transactionClass - Class of the transaction
      Returns:
      true when the transaction class is valid for the statement implementation.
    • setTransaction

      public final void setTransaction(FbTransaction newTransaction) throws SQLException
      Description copied from interface: FbStatement
      Associates a transaction with this statement
      Specified by:
      setTransaction in interface FbStatement
      Parameters:
      newTransaction - The transaction
      Throws:
      SQLException
    • setTimeout

      public void setTimeout(long statementTimeout) throws SQLException
      Description copied from interface: FbStatement
      Sets the statement timeout.

      The statement timeout value is ignored in implementations that do not support timeouts. If the provided timeout value is greater than supported (eg greater than ‭4294967295‬ milliseconds on Firebird 4), the implementation should behave as if zero (0) was set, but still report the original value.

      The configured timeout only affects subsequent executes on this statement. The timeout includes time spent between reading from the result set.

      Specified by:
      setTimeout in interface FbStatement
      Parameters:
      statementTimeout - Timeout value in milliseconds
      Throws:
      SQLException - If the value is less than zero, this statement is closed, or a database access error occurs
    • getTimeout

      public long getTimeout() throws SQLException
      Description copied from interface: FbStatement
      Gets the current statement timeout for this statement.

      This method will only return the current statement timeout value for this method, it will not consider attachment or connection level timeouts. This is an implementation decision that might change in a point release.

      Specified by:
      getTimeout in interface FbStatement
      Returns:
      The configured timeout in milliseconds; read the documentation in FbStatement.setTimeout(long)
      Throws:
      SQLException - If this statement is closed, or a database access error occurs
      See Also:
    • setCursorName

      public final void setCursorName(String cursorName) throws SQLException
      Sets the named cursor name for this statement.

      This method takes out a lock, and checks statement validity, then calls setCursorNameImpl(String), and stores the cursor name on successful completion. Any exceptions will be notified on exceptionListenerDispatcher. To override the behaviour of this method, implement/override setCursorNameImpl(String).

      Specified by:
      setCursorName in interface FbStatement
      Parameters:
      cursorName - Name of the cursor
      Throws:
      SQLException - If this statement is closed, or if the cursor name is set and cursorName is different from the current cursor name
    • setCursorNameImpl

      protected abstract void setCursorNameImpl(String cursorName) throws SQLException
      Implementation of setCursorName(String).

      The caller of this method will take out the lock, check statement validity and call exceptionListenerDispatcher for exceptions, so implementations of this method do not need to do so.

      Parameters:
      cursorName - Name of the cursor
      Throws:
      SQLException - If this statement is closed, or if the cursor name is set and cursorName is different from the current cursor name
    • getCursorName

      protected final String getCursorName()
      Gets the cursor name.

      The cursor name is cleared by a new statement prepare.

      Returns:
      the current cursor name
      Since:
      6
    • getAllowedTimeout

      protected long getAllowedTimeout() throws SQLException
      Returns:
      The timeout value, or 0 if the timeout is larger than supported
      Throws:
      SQLException - If the statement is invalid
    • parseStatementInfo

      protected void parseStatementInfo(byte[] statementInfoResponse) throws SQLException
      Parse the statement info response in statementInfoResponse. If the response is truncated, a new request is done using getStatementInfoRequestItems()
      Parameters:
      statementInfoResponse - Statement info response
      Throws:
      SQLException
    • hasSingletonResult

      protected final boolean hasSingletonResult()
      Returns:
      true if this is a stored procedure (or other singleton result producing statement) with at least 1 output field
    • hasFields

      protected final boolean hasFields()
      Returns:
      true if this statement has at least one output field (either singleton or result set)
    • signalExecute

      protected final OperationCloseHandle signalExecute()
      Signals the start of an execute for this statement.
      Returns:
      OperationCloseHandle handle for the operation
    • signalFetch

      protected final OperationCloseHandle signalFetch()
      Signals the start of a fetch for this statement.
      Returns:
      OperationCloseHandle handle for the operation
    • signalAsyncFetchStart

      protected final OperationCloseHandle signalAsyncFetchStart()
    • signalAsyncFetchComplete

      protected final OperationCloseHandle signalAsyncFetchComplete()