Module org.firebirdsql.jaybird
Package org.firebirdsql.gds.ng.wire

# Class InlineBlob

java.lang.Object
org.firebirdsql.gds.ng.wire.InlineBlob

All Implemented Interfaces:
  `AutoCloseable`, `FbBlob`, `ExceptionListenable`

@NullMarked public final class InlineBlob extends Object implements FbBlob
Implementation of `FbBlob` to hold an inline blob.

This blob may remain open on transaction end or database detach. However, this is considered an implementation detail which may change in point releases.

Since:
  6.0.2
Author:
  Mark Rotteveel

- ## Nested Class Summary

  ## Nested classes/interfaces inherited from interface org.firebirdsql.gds.ng.FbBlob

  `FbBlob.SeekMode`

- ## Field Summary

  ### Fields inherited from interface org.firebirdsql.gds.ng.FbBlob

  `NO_BLOB_ID`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `InlineBlob(FbDatabase database, long blobId, int transactionHandle, byte[] info, byte[] data)`
  Creates an inline blob.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `addExceptionListener(ExceptionListener listener)`
  Adds an exception listener to this object.
  `void`
  `cancel()`
  Cancels an output blob (which means its contents will be thrown away).
  `void`
  `close()`
  Closes the blob.
  `InlineBlob`
  `copy()`
  `int`
  `get(byte[] b, int off, int len)`
  Reads content from the blob into `b` starting at `off` for `len` bytes.
  `int`
  `get(byte[] b, int off, int len, float minFillFactor)`
  Variant of `FbBlob.get(byte[], int, int)` to exert some control over the number of requests performed.
  `long`
  `getBlobId()`
  Returns the blob id.
  `byte[]`
  `getBlobInfo(byte[] requestItems, int bufferLength)`
  Request blob info.
  `<T> T`
  `getBlobInfo(byte[] requestItems, int bufferLength, InfoProcessor<T> infoProcessor)`
  Request blob info.
  `FbDatabase`
  `getDatabase()`
  `int`
  `getHandle()`
  Returns the blob handle identifier.
  `int`
  `getMaximumSegmentSize()`
  The maximum segment size allowed by the protocol for `FbBlob.getSegment(int)` and `FbBlob.putSegment(byte[])`.
  `byte[]`
  `getSegment(int sizeRequested)`
  Gets a segment of blob data.
  `int`
  `getTransactionHandle()`
  `boolean`
  `isEof()`
  `boolean`
  `isOpen()`
  `boolean`
  `isOutput()`
  `long`
  `length()`
  Requests the blob length from the server.
  `void`
  `open()`
  Opens an existing input blob, or creates an output blob.
  `void`
  `put(byte[] b, int off, int len)`
  Writes content of `b` starting at `off` for `length` bytes to the blob.
  `void`
  `putSegment(byte[] segment)`
  Writes a segment of blob data.
  `void`
  `removeExceptionListener(ExceptionListener listener)`
  Removes an exception listener to this object.
  `void`
  `seek(int offset, FbBlob.SeekMode seekMode)`
  Performs a seek on a blob with the specified `seekMode` and `offset`.

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Constructor Details

  - ### InlineBlob

    public InlineBlob(FbDatabase database, long blobId, int transactionHandle, byte[] info, byte[] data)
    Creates an inline blob.
    Parameters:
      `database` - database that created this blob
      `blobId` - blob id
      `transactionHandle` - handle of the transaction for which this blob is valid
      `info` - blob info (cannot be `null`), if empty an array containing `isc_info_end` will be used
      `data` - actual blob data without segments (cannot be `null`)

- ## Method Details

  - ### getBlobId

    public long getBlobId()
    Description copied from interface: `FbBlob`
    Returns the blob id.

    For output blobs, this will return `FbBlob.NO_BLOB_ID` (`0L`) if the blob wasn't opened yet, or if the blob is deferred opened (client-side only). The value `FbBlob.NO_BLOB_ID` is technically invalid, but Firebird will handle it as an empty blob (both for input and output).

    Specified by:
      `getBlobId` in interface `FbBlob`
    Returns:
      The Firebird blob id

  - ### getTransactionHandle

    public int getTransactionHandle()
    Returns:
      the transaction handle this inline blob is valid for

  - ### getHandle

    public int getHandle()
    Returns the blob handle identifier.

    If the blob wasn't opened yet, this will return `0`. If the blob was deferred opened (client-side only), this will return an invalid blob handle value (e.g. `0xFFFF`, though this value is potentially protocol/implementation specific).

    An inline blob has no server-side counterpart, so we generate a value greater than 65535 as its handle.

    Specified by:
      `getHandle` in interface `FbBlob`
    Returns:
      The Firebird blob handle identifier

  - ### getDatabase

    public FbDatabase getDatabase()
    Specified by:
      `getDatabase` in interface `FbBlob`
    Returns:
      The database connection that created this blob

  - ### open

    public void open() throws SQLException
    Description copied from interface: `FbBlob`
    Opens an existing input blob, or creates an output blob.
    Specified by:
      `open` in interface `FbBlob`
    Throws:
      `SQLException` - If the blob is already open, this is a (closed) output blob and it already has a blobId, the transaction is not active, or a database connection error occurred

  - ### isOpen

    public boolean isOpen()
    Specified by:
      `isOpen` in interface `FbBlob`
    Returns:
      `true` if this blob is currently open.

  - ### isEof

    public boolean isEof()
    Specified by:
      `isEof` in interface `FbBlob`
    Returns:
      `true` if this blob has reached the end or has been closed, always `true` for an open output blob.

  - ### close

    public void close()
    Description copied from interface: `FbBlob`
    Closes the blob.

    Closing an already closed blob is a no-op.

    Specified by:
      `close` in interface `AutoCloseable`
    Specified by:
      `close` in interface `FbBlob`

  - ### cancel

    public void cancel()
    Description copied from interface: `FbBlob`
    Cancels an output blob (which means its contents will be thrown away).

    Calling cancel on an input blob will close it. Contrary to `FbBlob.close()`, calling cancel on an already closed (or cancelled) blob will throw an `SQLException`.

    Specified by:
      `cancel` in interface `FbBlob`

  - ### isOutput

    public boolean isOutput()
    Specified by:
      `isOutput` in interface `FbBlob`
    Returns:
      `true` if this is an output blob (write only), `false` if this is an input blob (read only)

  - ### getSegment

    public byte[] getSegment(int sizeRequested) throws SQLException
    Description copied from interface: `FbBlob`
    Gets a segment of blob data.

    When `sizeRequested` exceeds `FbBlob.getMaximumSegmentSize()` it is silently reduced to the maximum segment size.

    Specified by:
      `getSegment` in interface `FbBlob`
    Parameters:
      `sizeRequested` - Requested segment size (> 0).
    Returns:
      Retrieved segment (size may be less than requested)
    Throws:
      `SQLException` - If this is an output blob, the blob is closed, the transaction is not active, or a database connection error occurred.
    See Also:
      - `FbBlob.get(byte[], int, int)`

  - ### get

    public int get(byte[] b, int off, int len) throws SQLException
    Description copied from interface: `FbBlob`
    Reads content from the blob into `b` starting at `off` for `len` bytes.

    Implementations must read the requested number of bytes (`len`), unless end-of-blob is reached before the requested number of bytes were read. The return value of this method is the actual number of bytes read.

    If the implementation cannot perform reads without additional allocation, it should use at most `DatabaseConnectionProperties.getBlobBufferSize()` as an internal buffer. If the implementation can perform reads without additional allocation, it is recommended it performs reads using (at most) `FbBlob.getMaximumSegmentSize()`.

    Contrary to similar methods like `InputStream.read(byte[], int, int)`, this method returns `0` when no bytes were read if end-of-blob is reached without reading any bytes, not `-1`.

    Given this method attempts to fulfill the entire request for `len` bytes, it may not always be efficient. For example, requests near multiples of the maximum segment size (or blob buffer size) may result in a final request for just a few bytes. This is not a problem if the entire blob is requested at once, but for intermediate buffering it might be better not to do that final request, and instead work with a smaller number of bytes than requested. For those cases, use `FbBlob.get(byte[], int, int, float)`.

    Specified by:
      `get` in interface `FbBlob`
    Parameters:
      `b` - target byte array
      `off` - offset to start
      `len` - number of bytes
    Returns:
      actual number of bytes read; this will only be less than `len` when end-of-blob was reached
    Throws:
      `SQLException` - for database access errors, if `off < 0`, `len < 0`, or if `off + len > b.length`

  - ### get

    public int get(byte[] b, int off, int len, float minFillFactor) throws SQLException
    Description copied from interface: `FbBlob`
    Variant of `FbBlob.get(byte[], int, int)` to exert some control over the number of requests performed.

    This method will request segments until at least `(int) (minFillFactor * len)` bytes have been retrieved, or end-of-blob is reached. This method is intended as an alternative to `FbBlob.get(byte[], int, int)` where avoiding the potential inefficiencies of that method are preferred over getting all the requested `len` bytes.

    If the implementation cannot perform reads without additional allocation, it should use at most `DatabaseConnectionProperties.getBlobBufferSize()` as an internal buffer. If the implementation can perform reads without additional allocation, it is recommended it performs reads using (at most) `FbBlob.getMaximumSegmentSize()`.

    Contrary to similar methods like `InputStream.read(byte[], int, int)`, this method returns `0` when no bytes were read if end-of-blob is reached without reading any bytes, not `-1`.

    Specified by:
      `get` in interface `FbBlob`
    Parameters:
      `b` - target byte array
      `off` - offset to start
      `len` - number of bytes
      `minFillFactor` - minimum fill factor (`0 < minFillFactor <= 1`)
    Returns:
      actual number of bytes read, this method returns at least `(int) (minFillFactor * len)` bytes, unless end-of-blob is reached
    Throws:
      `SQLException` - for database access errors, if `off < 0`, `len < 0`, or if `off + len > b.length`, `minFillFactor <= 0`, or `minFillFactor > 1` or `minFillFactor is NaN`

  - ### putSegment

    public void putSegment(byte[] segment) throws SQLException
    Description copied from interface: `FbBlob`
    Writes a segment of blob data.

    Implementations must handle segment lengths exceeding `FbBlob.getMaximumSegmentSize()` by batching. This method should either call `put(segment, 0, segment.length)`, or produce the same effects as that call.

    Passing a section that is length 0 will throw an `SQLException`.

    Specified by:
      `putSegment` in interface `FbBlob`
    Parameters:
      `segment` - segment to write
    Throws:
      `SQLException` - if this is an input blob, the blob is closed, the transaction is not active, the segment is length 0, or a database connection error occurred
    See Also:
      - `FbBlob.put(byte[], int, int)`

  - ### put

    public void put(byte[] b, int off, int len) throws SQLException
    Description copied from interface: `FbBlob`
    Writes content of `b` starting at `off` for `length` bytes to the blob.

    Implementations must write all bytes to the blob, using multiple round-trips if necessary.

    If the implementation cannot perform writes without additional allocation, it should use at most `DatabaseConnectionProperties.getBlobBufferSize()` as an internal buffer. If the implementation can perform writes without additional allocation, it is recommended it performs reads using (at most) `FbBlob.getMaximumSegmentSize()`.

    Specified by:
      `put` in interface `FbBlob`
    Parameters:
      `b` - source byte array
      `off` - offset to start
      `len` - number of bytes
    Throws:
      `SQLException` - for database access errors, if `off < 0`, `len < 0`, or if `off + len > b.length`

  - ### seek

    public void seek(int offset, FbBlob.SeekMode seekMode) throws SQLException
    Description copied from interface: `FbBlob`
    Performs a seek on a blob with the specified `seekMode` and `offset`.

    Firebird only supports seek on stream blobs.

    Specified by:
      `seek` in interface `FbBlob`
    Parameters:
      `offset` - Offset of the seek, effect depends on value of `seekMode`
      `seekMode` - Value of `FbBlob.SeekMode`
    Throws:
      `SQLException` - If the blob is closed, the transaction is not active, or a database error occurred.

  - ### getMaximumSegmentSize

    public int getMaximumSegmentSize()
    Description copied from interface: `FbBlob`
    The maximum segment size allowed by the protocol for `FbBlob.getSegment(int)` and `FbBlob.putSegment(byte[])`.

    This value is not the segment size (optionally) defined for the column.

    Specified by:
      `getMaximumSegmentSize` in interface `FbBlob`
    Returns:
      The maximum segment size allowed for get or put.

  - ### getBlobInfo

    public <T> T getBlobInfo(byte[] requestItems, int bufferLength, InfoProcessor<T> infoProcessor) throws SQLException
    Description copied from interface: `FbBlob`
    Request blob info.
    Specified by:
      `getBlobInfo` in interface `FbBlob`
    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.

  - ### length

    public long length()
    Description copied from interface: `FbBlob`
    Requests the blob length from the server.
    Specified by:
      `length` in interface `FbBlob`
    Returns:
      Length of the blob.

  - ### getBlobInfo

    public byte[] getBlobInfo(byte[] requestItems, int bufferLength) throws SQLException
    Request blob info.

    Unknown blob info items are ignored, and only known items are returned.

    Specified by:
      `getBlobInfo` in interface `FbBlob`
    Parameters:
      `requestItems` - Array of info items to request
      `bufferLength` - Response buffer length to use
    Returns:
      Response buffer
    Throws:
      `SQLException`

  - ### addExceptionListener

    public 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 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

  - ### copy

    public InlineBlob copy()
    Returns:
      a copy of this inline blob, it is initially closed.