Jaybird 6.0.0-beta-1 is still in development, and intended for testing and evaluation purposes. We do not recommend this version for use in production environments.

If you come across any issues when using this version, please report them on https://github.com/FirebirdSQL/jaybird/issues.

1. Jaybird 6.0.x changelog

Changes per Jaybird 6 release. See also What’s new in Jaybird 6. For known issues, consult Known issues.

1.1. Jaybird 6.0.0-beta-1

Initial release for evaluation.

2. Known issues

  • Using a native connection with a Firebird 3.0 or higher client library to a Firebird 2.5 or older server may be slow to connect.

    Possible workarounds:

    • Use a native URL with the Firebird INET4 protocol (e.g. for DriverManager jdbc:firebird:native:inet4://<serverName>[:<portNumber>/<databaseName>).

    • Use the IPv4 address instead of the host name in the connection string

    • Use a Firebird 2.5 or earlier fbclient.

    This is caused by firebird#4971

3. Support

If you need support with Jaybird, join the Firebird-Java Google Group and mailing list. You can subscribe by sending an email to [email protected].

Looking for professional support of Jaybird? Jaybird is now part of the Tidelift subscription.

4. General Notes

Jaybird is a JDBC driver suite to connect to Firebird database servers from Java and other Java Virtual Machine (JVM) languages.

This driver does not work on Android, because it uses classes and features not available in Android.

4.1. About this version

Jaybird 6 is an incremental change from Jaybird 5.

The major changes and new features in Jaybird 6 are:

Upgrading from Jaybird 5 should be straightforward, but please make sure to read Compatibility changes before using Jaybird 6. If you’re using Jaybird with the native or embedded connections, you will need to make some additional changes. See also Upgrading from Jaybird 5 to Jaybird 6.

Bug reports about undocumented changes in behavior are appreciated. Feedback can be sent to the Firebird-java mailing list or reported on the issue tracker https://github.com/FirebirdSQL/jaybird/issues.

4.2. Supported Firebird versions

Jaybird 6.0.0-beta-1 was tested against Firebird 3.0.12, Firebird 4.0.5, Firebird 5.0.1 and a recent snapshot of Firebird 6.0, but should also support other Firebird versions from 3.0 and up. Firebird 2.5 and older are not supported.

Jaybird 6 will — by default — not connect to Firebird 2.5 or older. See also Pure Java will not connect to unsupported Firebird versions by default.

This driver does not support InterBase.

4.3. Supported Java versions

Jaybird 6 supports Java 17 and higher (JDBC 4.3). Support for earlier Java versions has been dropped.

Given the limited support period for Java 9 and higher versions, we limit support to Java 17, the most recent LTS version after Java 17, and the latest Java release. Currently, that means we support Java 17, Java 21, and Java 23.

Jaybird 5 will serve as a “long-term support” version for Java 8 and 11, with maintenance releases at least until the release of Jaybird 7.

Jaybird 6 provides libraries compiled for Java 17.

Jaybird 6 is modularized. The available modules are:

org.firebirdsql.jaybird

main Jaybird driver (jaybird-6.0.0-beta-1.jar)

org.firebirdsql.jaybird.chacha64

ChaCha64 wire encryption implementation (chacha64-plugin-6.0.0-beta-1.jar)

org.firebirdsql.jna

native and embedded protocol implementation using JNA (jaybird-native-6.0.0-beta-1.jar)

4.4. Specification support

Jaybird supports the following specifications:

Specification Notes

JDBC 4.3

All JDBC 4.3 methods for features supported by Firebird.

JTA 1.0.1

Implementation of javax.transaction.xa.XAResource interface via XADataSource implementation.

5. Getting Jaybird 6

5.1. Jaybird 6.0.0-beta-1

5.1.1. Maven

Jaybird 6.0.0-beta-1 is available on Maven Central.

groupId

org.firebirdsql.jdbc

artifactId

jaybird

version

6.0.0-beta-1

For example:

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>jaybird</artifactId>
    <version>6.0.0-beta-1</version>
</dependency>

If you want to use Type 2 support (native or embedded), you need to explicitly add jaybird-native as a dependency:

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>jaybird-native</artifactId>
    <version>6.0.0-beta-1</version>
</dependency>

For Windows and Linux, you can add the org.firebirdsql.jdbc:fbclient dependency on your classpath to provide the native libraries for the native protocol. Be aware that this dependency does not support embedded.

To enable the “ChaCha64” wire encryption support for pure Java connections, also add:

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>chacha64-plugin</artifactId>
    <version>6.0.0-beta-1</version>
</dependency>

5.2. Gradle

See also Maven.

Examples:

Main Jaybird artifact
implementation 'org.firebirdsql.jdbc:jaybird:6.0.0-beta-1'
Jaybird native artifact (native and embedded protocol)
implementation 'org.firebirdsql.jdbc:jaybird-native:6.0.0-beta-1'
ChaCha64 wire encryption plugin
implementation 'org.firebirdsql.jdbc:chacha64-plugin:6.0.0-beta-1'

5.2.1. Download

You can download the release of Jaybird from https://firebirdsql.org/en/jdbc-driver/

At minimum Jaybird 6 requires jaybird-6.0.0-beta-1.jar.

For native or embedded support, also add jaybird-native-6.0.0-beta-1.jar and jna-jpms-5.15.0.jar on your classpath or modulepath. See also Type 2 (native) and embedded driver.

For “ChaCha64” wire-encryption support with pure Java connections, also add chacha64-plugin-6.0.0-beta-1.jar and bcprov-jdk18on-1.78.1.jar.

6. Upgrading from Jaybird 5 to Jaybird 6

Please make sure to read Compatibility changes before upgrading to Jaybird 6.

6.1. Maven

Change the version of the dependency to 6.0.0-beta-1. If you’re using the artifact id jaybird-jdkXX, change it to jaybird.

When your Jaybird dependency defines the exclusion for javax.resource:connector-api (see example below), you can remove it as Jaybird no longer has a dependency on connector-api.

<exclusions>
    <exclusion>
        <groupId>javax.resource</groupId>
        <artifactId>connector-api</artifactId>
    </exclusion>
</exclusions>

For more detailed instructions, see also the information on Maven in Getting Jaybird 6.

If you use native or embedded, you now need to explicitly add jaybird-native as a dependency:

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>jaybird-native</artifactId>
    <version>6.0.0-beta-1</version>
</dependency>

If you use native or embedded, make sure to update your JNA dependency to version 5.15.0 and artifact id jna-jpms, or remove it altogether as the dependencies will now be pulled in through the jaybird-native artifact.

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-jpms</artifactId>
    <version>5.15.0</version>
</dependency>

Previous versions used artifactId jna instead of jna-jpms. Although both artifacts are nearly identical, the jna-jpms artifact provides a module-info.class, while the jna artifact does not. If you want to use Jaybird as a module, and use jaybird-native, make sure to use the jna-jpms artifact.

6.2. Manual install

If you manage your dependencies manually, you need to do the following:

  1. Replace the Jaybird 5 library with the Jaybird 6 version

    • jaybird-5.0.x.<java>.jar with jaybird-6.0.0-beta-1.jar

  2. If you use the NATIVE or EMBEDDED protocols, add the following JARs to the classpath or modulepath

    • jaybird-native-6.0.0-beta-1.jar

    • jna-jpms-5.15.0.jar from the lib directory of the distribution zip

      If you have an older version of JNA or a jna-5.15.0 instead of jna-jpms-5.15.0, make sure to remove and replace it with jna-jpms.

  3. To enable “ChaCha64” wire encryption support add the following JARs to the classpath or modulepath

    • chacha64-plugin-6.0.0-beta-1.jar

    • bcprov-jdk18on-1.78.1.jar from the lib directory of the distribution zip

6.3. Gotcha’s

If you find a problem while upgrading, or other bugs, please report it on https://github.com/FirebirdSQL/jaybird/issues.

For known issues, consult Known issues.

7. What’s new in Jaybird 6

For a full list of changes, see Milestone “v6-initial”.

7.1. Changes in version numbering

The minimum supported Java version of Jaybird 6 is Java 17. Our expectation is that Java version specific artifacts are no longer needed. As a consequence, the Java version has been dropped from the version number. The full version and naming convention is documented in jdp-2023-01: Version Number and Naming Scheme

As a result of these new naming conventions, the following has changed:

  • Maven version: 6.0.0 (was 5.0.0.java8)

  • Distribution zip: jaybird-6.0.0.zip (was jaybird-5.0.0.java8.zip)

  • Jaybird: jaybird-6.0.0.jar (was jaybird-5.0.0.java8.jar)

  • Jaybird sources: jaybird-6.0.0-sources.jar (was jaybird-5.0.0.java8-sources.jar)

  • Jaybird javadoc: jaybird-6.0.0-javadoc.jar (was jaybird-5.0.0.java8-javadoc.jar)

Furthermore, the client name reported to Firebird is now Jaybird jaybird-6.0.0 (was: Jaybird jaybird-5.0.0.java8).

7.2. Java support

7.2.1. Java versions before 17 no longer supported

Support of Java versions before Java 17 was dropped.

7.2.2. Java 17 and higher

Jaybird 6 supports Java 17 and higher (JDBC 4.3). Most of the JDBC 4.3 features have been implemented (in as far as they are supported by Firebird).

Given the limited support period for Java 17 and higher versions, not all Java releases are formally supported, see Supported Java versions for details.

7.3. Firebird support

Support for Firebird 2.5 has been dropped. See also Support for Firebird 2.5 dropped.

Jaybird 6 supports Firebird 3.0, Firebird 4.0, and Firebird 5.0, and provides tentative support for Firebird 6.0.

Jaybird 6 will — by default — not connect to unsupported versions (that is, Firebird 2.5 or older). See also Pure Java will not connect to unsupported Firebird versions by default.

7.4. Pure Java will not connect to unsupported Firebird versions by default

The pure Java protocol will by default no longer try the wire protocol versions of unsupported Firebird versions. This means that — by default — only protocol version 13 (Firebird 3.0) — 18 (Firebird 5.0) are tried. As a result, attempts to connect to Firebird 2.5 or earlier will result in error “connection rejected by remote interface” (335544421 or isc_connect_reject).

The connection property enableProtocol can enable unsupported protocols, assuming a suitable protocol implementation is available on the classpath.

This connection property can have the following values:

  • A comma-separated list of additional protocol versions to try (e.g. "11,12"). The listed versions are tried in addition to the supported protocol versions. Non-integer values or unknown protocol versions are silently ignored.

    It is possible to use the “masked” protocol version (e.g. "32780" for protocol version 12). However, we recommend using the unmasked version (e.g. "12" for protocol version 12).

  • "*" — enable all available protocol versions

  • null or empty string ("") — default behaviour, only use supported protocols

A different default value of enableProtocol can be set using the system property org.firebirdsql.jdbc.defaultEnableProtocol. This system property is checked each time a connection configuration is created, so it can be changed at runtime. If you use a Jaybird DataSource implementation, it uses the value at the time the DataSource is created; if you use DriverManager — this can include third-party data sources, it uses the value at the time the connection is created.

Given these protocol versions and their Firebird versions are not supported, there is no guarantee that the driver will function correctly when an unsupported protocol is enabled. Especially things like database metadata could use features that are not supported by older Firebird versions. We recommend upgrading your Firebird version, or downgrading to a Jaybird version which still supports your Firebird version.

For maximum compatibility, it is recommended to either use "*", or to make sure to include the maximum protocol version of your Firebird version.

Unsupported protocol versions may be removed in future major releases of Jaybird.

Table 1. Firebird versions and protocol versions
Firebird version Maximum protocol

1.0 — 2.0

10

2.1

11

2.5

12

3.0

15[1][2]

4.0

16[3]

5.0

18

7.5. NATIVE and EMBEDDED support moved to a separate artifact

The NATIVE (JDBC URL prefix jdbc:firebird[sql]:native:) and EMBEDDED (JDBC URL prefix jdbc:firebird[sql]:embedded:) protocol implementations have been moved to a separate artifact, org.firebirdsql.jdbc:jaybird-native.

If you use native or embedded connections using Jaybird, you will need to explicitly add the appropriate Maven dependency (or jaybird-native-6.0.0-beta-1.jar and jna-jpms-5.15.0.jar) to your classpath.

See also Getting Jaybird 6.

7.6. OOREMOTE (OpenOffice/LibreOffice protocol) removed

The OOREMOTE protocol (JDBC URL prefix jdbc:firebird[sql]:oo:) has been removed in Jaybird 6.

The recommended replacement is to use LibreOffice and the builtin “Firebird External” connection option in LibreOffice Base, instead of the “JDBC” option with Jaybird on the classpath of LibreOffice.

7.7. Modularization of Jaybird

Jaybird now uses real Java modules.

The available modules are:

org.firebirdsql.jaybird

main Jaybird driver (jaybird-6.0.0-beta-1.jar)

org.firebirdsql.jaybird.chacha64

ChaCha64 wire encryption implementation (chacha64-plugin-6.0.0-beta-1.jar)

org.firebirdsql.jna

native and embedded protocol implementation using JNA (jaybird-native-6.0.0-beta-1.jar)

We’ve tried to be liberal with exporting packages from Jaybird, but we have decided not to export some packages because we think they shouldn’t normally be accessed by users of Jaybird. If you run into problems with packages not being exported, please report this on firebird-java or on https://github.com/FirebirdSQL/jaybird/issues. Please include an explanation why you need to access a specific package. As a workaround, you can also add exports yourself with the --add-exports commandline option of java and javac and the Add-Exports manifest entry of your application (similar options exist for opens).

When the Jaybird JAR files are on the classpath, they should behave as before. For modular applications, once added to the modulepath instead of the classpath, they will behave in a more restricted fashion.

If you use Jaybird only as a JDBC driver (through java.sql.DriverManager), having the driver on the modulepath and having requires java.sql in the module-info.java of your application should be sufficient. If your code uses classes and other types from Jaybird, you will also need to add requires org.firebirdsql.jaybird.

The ChaCha64 plugin, org.firebirdsql.jaybird.chacha64, will just need to be present on the modulepath to be loaded.

The same goes for the native protocol module, org.firebirdsql.jna, but we recommend you only add it to the modulepath if you actually need native or embedded access. You also need to replace any jna-<version>.jar with jna-jpms-5.15.0.jar (the modular variant of JNA).

If you use org.firebirdsql.jna to implement a Firebird embedded provider, you’ll need to add requires org.firebirdsql.jna and an appropriate provides org.firebirdsql.jna.embedded.spi.FirebirdEmbeddedProvider with <classname> in your module-info.java. For compatibility with use on the classpath, it is recommended to also provide the META-INF/services/org.firebirdsql.jna.embedded.spi.FirebirdEmbeddedProvider file.

For more information, see also jdp-2023-13: Modularization of Jaybird.

7.8. Connection property createDatabaseIfNotExist

The Boolean connection property createDatabaseIfNotExist instructs Jaybird to attempt to create the database if it does not exist yet. This property can be used in the JDBC URL, in the Properties object passed to DriverManager, and can be set on data sources.

Although Jaybird already allowed you to create databases using org.firebirdsql.management.FBManager, this is not always accessible, for example in tools or libraries that only expose or use the JDBC API. This new property provides an alternative way to create databases.

Jaybird allows you to set or override connection properties specifically for creating the database by suffixing the property name with @create (case-sensitive). This can be used to set configuration properties that are only relevant for creating the database, or — for example — to use a different user or role for creating the database than used for normal connections.

As an example:

String jdbcUrl = "jdbc:firebird://localhost/exampledb" +
    "?createDatabaseIfNotExist=true&" +
    "user@create=sysdba&password@create=masterkey";
try (Connection connection = DriverManager.getConnection(
    jdbcUrl, "normaluser", "password")) {
  // ...
}

If the database already exists, the connection will be made with user normaluser, but if the database does not exist, the database and the connection will be created with user sysdba.

The errors Firebird returns do not make it possible to determine definitively if the database does not exist, or if there is another reason that the connection failed. Jaybird applies some simple rules to exclude some classes of errors, and not attempt to create a database in those cases.

If you find cases where you think Jaybird should not — or on the contrary, should — attempt to create a database, please report them on https://github.com/FirebirdSQL/jaybird/issues.

For more information, see also jdp-2024-02: Create database through JDBC URL.

7.9. Report actual process ID (pid)

The pure Java implementation will now report the actual process ID (pid) in connection property isc_dpb_process_id. The native implementation already did this.

For pure Java connections, the reported process ID can be overridden using the connection property processId or the system property org.firebirdsql.jdbc.pid. This feature is retained for backwards compatibility.

When a SecurityManager is installed, the entire call-chain needs to have the RuntimePermission("manageProcess") to obtain the process ID in pure Java connections. If this permission check fails, Jaybird will silently ignore it and not set the isc_dpb_process_id based on the actual process ID.

7.10. Logging facade removed

The logging facade from package org.firebirdsql.logging has been removed, and is replaced by the Java Platform Logging API (JEP 264).

The Java Platform Logging API by default logs to java.util.logging, but it is possible to plug in different logging platforms. For example, Log4j provides the log4j-jpl dependency which will replace the default binding to java.util.logging with one to Log4j.

With this change, Jaybird no longer provides an option to specify a custom logger implementation, so the system property org.firebirdsql.jdbc.loggerImplementation is no longer supported. If you need a custom logger, you will need to implement java.lang.System.Logger and java.lang.System.LogFinder and provide the necessary service loader definition (see the Java documentation for details).

The system properties org.firebirdsql.jdbc.forceConsoleLogger and org.firebirdsql.jdbc.disableLogging are also no longer supported. Equivalent behaviour is achieved by configuring the active logging library.

7.11. Support for ChaCha64 wire encryption

Support for the “ChaCha64” wire encryption — introduced in Firebird 4.0.1 — was added for the PURE_JAVA protocol. Given this requires a dependency on the Bouncy Castle provider (bcprov-jdk18on), the plugin is made available as a separate artifact: org.firebirdsql.jdbc:chacha64-plugin on Maven or chacha64-plugin-6.0.0-beta-1.jar in the distribution zip.

When deploying manually, please make sure to also include the bcprov-jdk18on-1.78.1.jar from the lib directory of the distribution zip on the classpath.

Limitations of ChaCha lead to introduction of ChaCha64

The “ChaCha” wire encryption introduced in Firebird 4.0 and Jaybird 5 uses a 96-bit nonce and 32-bit counter. This 32-bit counter limits the amount of data you can transfer to a maximum of 256 GiB. As the Firebird wire protocol doesn’t support “re-keying” the encryption plugin, this means the connection breaks if 256GiB has been sent or received. This breaking is done to prevent key re-use, which could make the data stream vulnerable to certain types of cryptological analysis.

To address this, Firebird 4.0.1 added the “ChaCha64” wire encryption, which uses a 64-bit nonce and 64-bit counter.

As part of this change, Jaybird is now capable of loading EncryptionPluginSpi instances using the service loader mechanism. The API of EncryptionPluginSpi and EncryptionPlugin and other classes and interfaces in package org.firebirdsql.gds.ng.wire.crypt should still be considered unstable and internal API, so use it at your own risk to implement your own plugins. If you want to use it for implementing your own encryption plugins, let us know on firebird-java. We can then look at stabilizing the API and considering it formally a public API.

7.12. Opt-in feature for package information in DatabaseMetaData

Firebird 3.0 added packages, which can contain stored procedures and functions. The JDBC API does not provide a standard way of accessing information about packages, or the routines defined in packages. Instead of adding additional Jaybird-specific metadata methods, we’ve added an “opt-in” feature that provides access through normal metadata methods, using the “catalog” to report packages.

This feature can be enabled by setting the connection property useCatalogAsPackage to true. When this connection property is enabled, the DatabaseMetaData of that connection will have the following changes in behaviour:

  • getCatalogs() lists packages, with package names in TABLE_CAT.

  • getFunctions, getFunctionColumns, getProcedures, and getProcedureColumns include information on procedures or functions in packages

    • Columns FUNCTION_CAT/PROCEDURE_CAT will report:

      • For packaged procedures and functions — the package name

      • For normal (non-package) procedures and functions — an empty string instead of null (because of the following rule)

    • If parameter catalog is "" (empty string), only normal stored procedures or stored functions are reported.

    • If parameter catalog is null, both packaged and normal stored procedures or stored functions are reported.

    • For other values of parameter catalog, these metadata methods will only return procedures, functions, or their columns of the specified package (exact match, case-sensitive; not a LIKE pattern)

    • For normal (non-package) procedures and functions, the SPECIFIC_NAME column will be the unquoted function or procedure name (same as when useCatalogAsPackage is not enabled), and for packaged procedures and functions, it will be quoted-package-name + '.' + quoted-routine-name (e.g. "SOME_PACKAGE"."SOME_FUNCTION")

  • getCatalogSeparator() returns "." (string with period).

  • getCatalogTerm() returns "PACKAGE".

  • isCatalogAtStart() returns true.

  • getMaxCatalogNameLength() returns 31 or 63 depending on the max identifier length of the database.

  • supportsCatalogsInDataManipulation() returns true (i.e. access selectable stored procedures and functions from packages).

  • supportsCatalogsInProcedureCalls() returns true.

  • The other supportsCatalogsIntype() methods continue to return false.

  • Other metadata methods with a catalog parameter continue to ignore it, just like they do when useCatalogAsPackage is disabled.

The useCatalogAsPackage connection property does not result in any other behaviour.

Keep in mind, that this is non-standard behaviour, and standard JDBC tools or libraries may not work correctly when this property is enabled. This feature may be discontinued and removed in the future if Jaybird needs to implement “real” catalogs (e.g. because Firebird started supporting catalogs).

7.13. Asynchronous fetching

For pure Java connections, non-holdable forward-only result sets now perform asynchronous fetches. Asynchronous fetches are implemented for protocol implementation version 11 and higher (i.e. Firebird 2.1 or higher), but are formally only supported for protocol version 13 and higher (i.e. Firebird 3.0 or higher).

In normal usage of a result set, the first fetch will be a normal synchronous fetch. If certain conditions are met, subsequent fetches will be performed asynchronously.

The conditions for using asynchronous fetch are considered an implementation detail and may change in point releases. In Jaybird 6.0.0, the conditions to enable asynchronous fetching are:

  1. The result set has type FORWARD_ONLY.

  2. The result set does not have a cursor name set.

  3. Any synchronous fetch on the statement cursor retrieved at least 15 rows. Be aware that the server may return fewer rows than the configured fetch size (default is 400), depending on Firebird version, row size and other factors.

When the asynchronous fetch is triggered is also an implementation detail and may change in point releases. In Jaybird 6.0.0, the conditions to perform an asynchronous fetch are:

  • Size of the row buffer is equal to the “low-water mark”.

    This “low-water mark” is calculated as ~33% of the maximum number of rows returned by previous fetches, with a minimum of 10 rows.

    As a consequence of this condition, reducing the fetch size equal to or less than the “low-water mark” may cause asynchronous fetches to stop being triggered, as the buffer size may remain smaller than this “low-water mark” (this effect may be reduced if there is other activity on the connection after the asynchronous fetch was performed). In that case a synchronous fetch is triggered when the buffer is empty.

  • Fetch size at time of async fetch is larger than 1. This may be the configured fetch size, or the fetch size derived taking into account the configured maximum row count.

Native connections do not support this type of asynchronous fetching, but fbclient itself provides a different form of internal asynchronous fetching for native connections.

7.14. Blob performance improvements

7.14.1. Reading blobs

Performance of reading blobs has been improved, especially when using getBytes on ResultSet or Blob, or getString on ResultSet or Clob, or reading from a blob input stream with read(byte[], int, int) and similar methods with a byte array and requested length greater than 50% of the configured blobBufferSize.

Testing on a local network (Wi-Fi) shows an increase in throughput of roughly 50-100% for reading large blobs with the default blobBufferSize of 16384.

These throughput improvements were only realised in the pure Java protocol, because there we had the opportunity to avoid all additional allocations by writing directly from the network stream into the destination byte array, and this allows us to ignore the configured blobBufferSize and use up to the maximum request size of 65535 bytes instead.

This is not possible for the JNA-based protocols (native/embedded), as the implementation requires a direct byte buffer to bridge to the native API, and thus we can’t ignore the blobBufferSize. We were able to realise some other optimizations (in both pure Java and JNA), by avoiding allocation of a number of intermediate objects, but this has only marginal effects on the throughput.

7.14.2. Writing blobs

Performance of writing blobs was improved, especially when using setBytes on PreparedStatement, ResultSet or Blob, or setString on PreparedStatement, ResultSet or Clob, or writing to a blob output stream with write(byte[], int, int) and similar methods with a byte array larger than the configured blobBufferSize. A smaller improvement was made when using arrays larger than 50% of the blobBufferSize.

Testing on a local network (Wi-Fi) shows an increase in throughput of roughly 300-400% for writing large blobs with the default blobBufferSize of 16384. The improvement is not available for all methods of writing blobs, for example using ResultSet.setBinaryStream does not see this improvement, as it relies on the blobBufferSize for transferring the blob content.

Most of these throughput improvements were only realised in the pure Java protocol, because there we had the opportunity to avoid all additional allocations by writing directly from the source byte array to the network stream, and this allows us to ignore the configured blobBufferSize and use up to the maximum segment size of 65535 bytes instead.

For the JNA-based protocols (native/embedded) a smaller throughput improvement was realised, by using the maximum segment size for the first roundtrip if the array write used offset 0. If the length is larger than the maximum segment size, or if the offset is non-zero, we need to allocate a buffer (for subsequent segments in case offset is 0), and thus cannot ignore the blobBufferSize.

Similar to the improvements for reading, we were also able to realise some other optimizations (in both pure Java and JNA), by avoiding allocation of a number of intermediate objects, but this has only marginal effects on the throughput.

7.14.3. Minimum blobBufferSize 512 bytes

As part of the performance improvements, a minimum blobBufferSize of 512 bytes was introduced. Configuring values less than 512 will be ignored and use 512 instead.

7.14.4. Maximum segment size raised

For connections to Firebird 3.0 and higher, the maximum segment size was raised from 32765 to 65535 bytes to match the maximum segment size supported by Firebird.

The maximum segment size is the maximum size for sending segments (put) to the server. Due to protocol limitations, retrieving segments from the server (get) is two bytes (or multiples of two bytes) shorter[4].

7.14.5. Effectiveness of blobBufferSize larger than maximum segment size

Previously, when reading blobs, a blobBufferSize larger than the maximum segment size was effectively ignored. Now, when reading through an input stream, a blobBufferSize larger than the maximum segment size can be used.

Jaybird will use one or more roundtrips to fill the buffer. To avoid inefficient fetches, a minimum of 90% of the buffer size will be filled up to the blobBufferSize. This change is not likely to improve performance, but it may allow for optimizations when reading or transferring data in large chunks.

In general, setting the blobBufferSize larger than 65535 bytes will likely not improve performance.

7.14.6. Internal API changes for FbBlob

Two new methods were added to FbBlob:

int get(byte[] b, int off, int len)

populates the array b, starting at off, for the requested len bytes from the blob, and returns the actual number of bytes read. This method will read until len bytes have been read, and only return less than len when end-of-blob was reached.

int get(byte[] b, int off, int len, float minFillFactor)

populates the array b, starting at off, for at least minFillFactor * len bytes (up to len bytes) from the blob, and returns the actual number of bytes read.

void put(byte[] b, int off, int len)

sends data from array b to the blob, starting at off, for the requested len bytes.

The documentation of method FbBlob.putSegment(byte[]) contradicted itself, by requiring implementations to batch larger arrays, but also requiring them to throw an exception for larger arrays, and the actual implementations provided by Jaybird threw an exception. This contradiction has been removed, and the implementations will now send arrays longer than the maximum segment size to the server in multiple put requests.

7.15. Support for executing transaction management statements

In Jaybird 5 and earlier, it was not possible to execute the transaction management statements COMMIT, ROLLBACK (without RETAIN or a savepoint) and SET TRANSACTION. For COMMIT and ROLLBACK it would seem to work, but subsequent use of the connection would then break because the connection assumed it still had an active transaction.

Formally, the JDBC specification says — paraphrased — that if something can be done through the JDBC API, that those API methods should be used; you should not use equivalent statements. However, from a perspective of flexibility, and for example for executing scripts, it can be useful to be able to execute those statements.

Jaybird now optionally allows you to execute COMMIT [WORK], ROLLBACK [WORK] and SET TRANSACTION […​]. By default, Jaybird 6 explicitly rejects attempts to execute those statements, instead of the half-working/half-broken situation of previous versions.

To allow execution of COMMIT [WORK], ROLLBACK [WORK] and SET TRANSACTION […​], the connection property allowTxStmts needs to be set to true. This can be done using a JDBC connection property allowTxStmts, or setAllowTxStmts(boolean) on DataSource instances.

Just because you can, doesn’t mean you should use this. For code solutions, you should use the normal methods in the JDBC API whenever possible. Only use this solution for scripts, or in case it is cumbersome or not possible to access the Jaybird extensions to the JDBC API to control the transaction configuration.

In the implementation, the use of COMMIT and ROLLBACK will not be executed as statements on the server, but instead call Connection.commit() and Connection.rollback(). The SET TRANSACTION statement — if allowed — is executed with execute immediate, and not through a statement handle.

Contrary to its name, and the SQL standard behaviour, Firebird’s SET TRANSACTION immediately starts a transaction.

Enabling this feature can also make it easier to use the table reservation feature, compared to FirebirdConnection.setTransactionParameters(TransactionParameterBuffer) or FirebirdConnection.setTransactionParameters(int, TransactionParameterBuffer), which requires access to the Jaybird API interfaces.

This feature has the following limitations:

  • Transaction management statements cannot be executed when auto-commit is enabled, or if the connection is participating in a distributed transaction. This is the same behaviour as implemented for Connection.commit() and Connection.rollback().

  • Executing COMMIT or ROLLBACK — when auto-commit is disabled — is silently ignored if there is no active transaction. This is the same behaviour as implemented for Connection.commit() and Connection.rollback().

  • SET TRANSACTION cannot be executed if there is an active transaction. In other words, you will need to call Connection.commit() or execute COMMIT (or roll back) before you can start a new transaction this way.

  • Transaction management statements are not supported by Statement.addBatch(String), PreparedStatement.addBatch(), and Connection.prepareCall(…​).

7.16. Configurable buffer sizes for the wire protocol

The sizes of a number of buffers used in the wire protocol were increased from 512 bytes to 8192 bytes. This specifically concerns:

  • wire compression — deflate (compression)

  • wire compression — inflate (decompression)

  • wire encryption — decrypt

    There is no such buffer for the reverse (encryption), as this is already handled by the general output buffer.

This change might not be desirable in all situations as it increases the total amount of memory per connection, or there can be reasons to further increase these buffers. To address this, we have added system properties to configure a number of buffers which were previously not configurable:

org.firebirdsql.wire.deflateBufferSize

Buffer size in bytes for deflate (compression). Has a minimum size of 512 and a default value of 8192.

org.firebirdsql.wire.inflateBufferSize

Buffer size in bytes for inflate (decompression). Has a minimum size of 512 and a default value of 8192.

org.firebirdsql.wire.decryptBufferSize

Buffer size in bytes for decryption. Has a minimum size of 512 and a default value 8192.

As the decryption input buffer determines the size of the decryption output buffer, the actual allocation is up to twice the specified value.

org.firebirdsql.wire.inputBufferSize

Buffer size in bytes for reading data from the socket. Has a minimum size of 1024 and a default value of 16384.

This property should not be confused with the socket buffer size (configurable with the socketBufferSize connection property). Setting this value higher than socketBufferSize is unlikely to have any benefits.

org.firebirdsql.wire.outputBufferSize

Buffer size in bytes for writing data. Has a minimum size of 1024 and a default value of 32767.

This property should not be confused with the socket buffer size (configurable with the socketBufferSize connection property). Contrary to the input buffer size, setting it higher than socketBufferSize might have performance benefits.

These properties need to be set before Jaybird is loaded and used (e.g. on the commandline with -‍D<propertyName>=<propertyValue).

The minimum sizes and default values should be considered an implementation detail and might change in a future major version.

The “deflate” and “inflate” buffers are only used when wire compression is enabled. The “decrypt” buffer is only applied when wire encryption is used (the default with Firebird 3.0 and higher).

The order of buffers for input is as follows:

Jaybird ⇐ [inflate ⇐] [decrypt ⇐] input ⇐ socket

The order of buffers for output is as follows:

Jaybird ⇒ output [⇒ deflate] ⇒ socket

A future version may introduce connection properties to control this per connection.

7.17. Broken connection detection for event manager

The event manager now attempts to detect if the underlying database connection is broken. Once a broken connection is detected, the event manager will attempt to close or forcibly disconnect itself and report itself as not connected.

For proper detection of some types of network problems in a timely manner, it may be necessary to configure the soTimeout of the event manager before connecting. When the createFor(Connection) method has been used, this can be configured through the soTimeout connection property, or — for pure Java connections only — the setNetworkTimeout method of the Connection object.

This detection depends on actual activity, like an event posting a new count, or a new event registration.

7.18. Connection property to specify native library path

A connection property nativeLibraryPath was added to specify the directory where fbclient (for native connections), or fbembed or fbclient (for embedded connections) can be loaded. If a file path is used instead of a directory path, the parent directory will be used for the search path. In other words, it is not possible to use it load a differently named library.

This property comes with a very important caveat: it only works for the first native or embedded connection (to a database or service) made within a JVM. Once any client library is loaded, that library is used for all subsequent native and embedded connections.

This property is only exposed as a JDBC property. For data sources, it needs to be set with setProperty(String, String) or setNonStandardProperty(String).

The primary use case for this property is for situations where configuring the system property jna.library.path is not easy to do (e.g. in third-party applications).

For embedded connections, if there is a valid FirebirdEmbeddedProvider on the classpath, it will be used instead of the location specified by nativeLibraryPath.

7.19. Rewritten client info properties support

Client info properties were introduced in JDBC 4.0 and implemented in Jaybird 2.2. This support has been rewritten to remove some limitations and correct some problems with the previous implementation.

The new implementation discerns two types of property names:

  1. without context; get/set in USER_SESSION context of RDB$GET/SET_CONTEXT

  2. with context, when the name ends in @USER_SESSION, @USER_TRANSACTION or @SYSTEM; get/set without that suffix in the specified context. Properties with multiple contexts (e.g. property@SYSTEM@USER_SESSION) are not allowed to prevent ambiguity. Everything else is a property without context.

A property named <name>@USER_SESSION is handled identical to <name>. The “without context” name is preferred and recommended for USER_SESSION properties, and Connection.getClientInfo() will use the “without context” name as the key for USER_SESSION properties.

A property named <name>@USER_TRANSACTION is set and get as <name> in context USER_TRANSACTION. When a connection is in auto-commit mode, attempts to set or get USER_TRANSACTION properties are ignored (nothing is stored, and null is returned without accessing the database).

A property named <name>@SYSTEM is retrieved as <name> in the context SYSTEM. Properties in the SYSTEM context are read-only, so they cannot be set. For Connection.setClientInfo(String, String), attempts to set a SYSTEM property result in a SQLClientInfoException, for Connection.setClientInfo(Properties), SYSTEM properties are silently ignored.

Attempts to retrieve non-existent properties, even from SYSTEM will return null and will not result in an exception.

A connection registers properties known to that specific connection. By default, only the JDBC-specified properties ApplicationName, ClientUser and ClientHostName (see also below) are known. A successful get or set of a property will register that property as a known property for the current connection only.

The method Connection.getClientInfo() will retrieve only known properties (the default properties and those registered for the current connection). It will not attempt to query or identify other variables registered in any context.

The method Connection.setClientInfo(Properties) clears (sets to NULL) known properties in USER_SESSION and — if not in auto-commit — USER_TRANSACTION if they are not included in the Properties object.

DatabaseMetaData.getClientInfoProperties() reports the JDBC-specified properties only; it will not report the additional properties registered for the current connection.

The JDBC-specified properties are:

ApplicationName

The name of the application currently utilizing the connection

ClientUser

The name of the user that the application using the connection is performing work for. This may not be the same as the username that was used in establishing the connection.

ClientHostname

The hostname of the computer the application using the connection is running on.

JDBC API documentation of java.sql.Connection

All JDBC-specified properties are get and set in USER_SESSION. On get of ApplicationName, if this property is not currently set in USER_SESSION, it falls back to get the value from CLIENT_PROCESS@SYSTEM. The CLIENT_PROCESS@SYSTEM value can be specified using the connection property processName or system property org.firebirdsql.jdbc.processName. The ClientUser and ClientHostname properties are considered application-specific and have no default value or fallback.

Compared to the previous implementation, the important differences are:

  • Connection.getClientInfo() now reports properties; the previous implementation always returned an empty Properties object.

  • Connection.getClientInfo(String) with a property name without context now queries only USER_SESSION; the previous implementation queried USER_TRANSACTION, and if not set, fell back to the value from USER_SESSION. To retrieve from USER_TRANSACTION in the new implementation, use <name>@USER_TRANSACTION.

  • Connection.setClientInfo(Properties) now clears known properties not included in the Properties object; the previous implementation only set the included properties.

  • Successful get or set of a property registers it as known property of the connection and influences behaviour of subsequent calls to getClientInfo() and setClientInfo(Properties) on that connection

  • DatabaseMetaData.getClientInfoProperties now reports the JDBC-specified properties, and nothing else; the previous implementation always returned an empty result set.

Connection pools and known connection properties

If you use a connection pool populated from org.firebirdsql.ds.FBConnectionPoolDataSource or org.firebirdsql.ds.FBXADataSource, the known properties are reset each time the connection is handed out by the pool. This assumes the pool uses getConnection() from PooledConnection/XAConnection each time it hands out the connection. This reset only removes the property name from the list of known properties, it does not clear the property values from USER_SESSION. If properties contain sensitive values you will need to explicitly clear them.

This reset is not applied when using a connection pool which is populated by different means (e.g. from DriverManager or from a normal javax.sql.DataSource like org.firebirdsql.ds.FBSimpleDataSource). If your connection pool implementation supports custom code to reset a connection, and you need known properties to reset when a connection is reused, make it call FirebirdConnection.resetKnownClientInfoProperties(), or call it yourself:

if (connection.isWrapperFor(FirebirdConnection.class)) {
    connection.unwrap(FirebirdConnection.class)
            .resetKnownClientInfoProperties();
}

In the future, Jaybird may be changed to also perform this reset in Connection.beginRequest() and/or Connection.endRequest().

7.20. TIMESTAMP fields now accept LocalDate and LocalTime

The JDBC specification does not specify support for LocalDate and LocalTime on TIMESTAMP (without time zone). However, when we introduced support for the java.time types, we implemented support for getting LocalDate and LocalTime (through getObject), but did not provide support for setting values of those types (through setObject) on TIMESTAMP.

We have now addressed this inconsistency, by also introducing support for setting these types on TIMESTAMP with the following behaviour:

  • setObject(…​, localTime) sets a LocalDateTime derived as LocalDate.EPOCH.atTime(localTime) (i.e. on 1970-01-01)

  • setObject(…​, localDate) sets a LocalDateTime derived as localDate.atStartOfDay() (i.e. at 00:00:00)

7.21. ResultSet in auto-commit no longer closed after last row

In previous Jaybird versions, iterating over a forward-only result set in auto-commit mode would implicitly close the result set after the last row was fetched — i.e. when next() returned false. This behaviour complied with the JDBC 3.0 requirements, but in JDBC 4.0 this requirement was removed, but still allowed.

In Jaybird 6, this implicit close has been removed. In auto-commit mode, a result set will now remain open until explicitly closed using ResultSet.close(), when any statement is executed, when the auto-commit mode is disabled, or by the close of the Statement or Connection.

As a result set close is an auto-commit boundary, this change may delay commit of the active transaction until another action on the connection. If you relied on this implicit close for correctness of your application, you may need to add an explicit call to ResultSet.close() — e.g. using try-with-resources.

7.22. Changes to behaviour of updatable scrollable result sets

Jaybird 5 introduced support for server-side scrollable cursors on Firebird 5.0 and higher in the pure Java protocol. This can be enabled using the connection property scrollableCursor=SERVER.

For implementation reasons, updatable server-side scrollable cursors had a different behaviour than the emulated client-side scrollable cursors. These differences are:

  • New rows are inserted at the end of the cursor; in emulated they were inserted immediately before the current row.

  • Deleted rows have an all-null marker row; in emulated the row was removed from the cursor.

  • The result set reports true for rowDeleted(), rowInserted() or rowUpdated() for — respectively — deleted, inserted or updated rows; in emulated these always reported false.

In Jaybird 6, this new behaviour is now also used for the updatable emulated scrollable cursors. The reason is that having two different sets of behaviours can be confusing, as it makes it impossible to switch between the two without having to account for the behavioural differences (either intentionally, or because you’re connecting with the native or embedded protocol, or to an older version of Firebird).

We’re considering to make server-side scrollable cursors the default in a future Jaybird version (Jaybird 7 or later).

7.23. Other fixes and changes

  • Improvement: Setting oversized strings on CHAR or VARCHAR parameters with character set UTF8 will now throw a DataTruncation exception on setString (and not set a value) instead of a SQLException with a “string right truncation” error on execute (#396)

    With this change, the behaviour for UTF8 is now consistent with that of single-byte character sets. For UTF8, the DataTruncation reports the transfer size and data size in Unicode codepoints. For other multibyte character sets, the DataTruncation reports those sizes in bytes. This change is not applied to UNICODE_FSS, as Firebird 3.0 and earlier do not enforce character length limits for this character set, only byte length limits.

    The setBytes method on CHAR and VARCHAR parameters only check the byte length limit.

  • Improvement: Implemented java.sql.Connection.abort(Executor) to forcibly abort a connection (#496)

    The java.sql.Connection is marked closed immediately, after which the executor is used to mark client-side statements and result sets as closed, and then closes the actual physical connection. The close of the physical connection is not a clean close and may result in “connection reset by peer” errors (e.g. error 10054 on Windows, error 104 on Linux) logged in firebird.log. Active transactions may not be rolled back immediately; this will be delayed until the server detects that the connection was closed. It is possible that some listeners are not informed of the connection, statement or result set close. When a security manager is active, calling abort requires the SQLPermission “callAbort”.

  • Changed: DatabaseMetaData.getTypeInfo() column FIXED_PREC_SCALE (column 11) now returns false for all data types except NUMERIC and DECIMAL (#551)

    This was done because of the stated requirement “can it be a money value”. Previously almost all types returned true (including — for example — BOOLEAN and TIMESTAMP, which are definitely not money types).

  • Consistent use of BigDecimal.valueOf(double) instead of a combination of new BigDecimal(double) and BigDecimal.valueOf(double) (#553)

  • Switched blob identification in message BLR from blr_quad to blr_blob2 (#726)

  • Removed finalize() methods and — where it made sense — replaced them with use of Cleaner (#727)

  • Fixed: FBResultSetMetaData.getPrecision would always estimate the precision of NUMERIC or DECIMAL columns instead of obtaining the actual precision if the column position was 71 or higher (#731)

    This fix was backported to Jaybird 5.0.5.

  • Optimized the query to retrieve extended field info for ResultSetMetaData.getPrecision to only retrieve columns of type NUMERIC or DECIMAL (#732)

    This improvement was backported to Jaybird 5.0.5.

  • Added methods List<String> getTypeAliasList() and List<String> getSupportedProtocolList() to GDSFactoryPlugin, and deprecated String[] getTypeAliases() and String[] getSupportedProtocols() for removal in Jaybird 7 or later

  • Fixed formatting of isc_formatted_exception to not repeat the original parameters of the exception (#749)

  • Added aliases ApplicationName and applicationName for connection property processName (#751)

  • Fixed: on CHAR fields, a too short value could be returned if the string contained one or more codepoints represented by surrogate pairs and the string length in char exceeded the maximum string length (#760)

    We now truncate the returned string if the codepoint count exceeds the maximum string length.

    This change was also backported to Jaybird 5.0.3.

  • Improvement: Do not reject attempts to read blob id 0 (#764)

    Previously, Jaybird rejected attempts to read blobs with blob id 0 (not on all code paths, for some only when assertions are enabled). Formally, blob id 0 is not a valid blob id, but in practice they can occur (e.g. due to bugs, or access components/drivers explicitly setting a blob column to id 0). Other drivers and tools simply send the requests for blob id 0 to the server, which then treats it as an empty blob. For consistency, we decided to let Jaybird handle it the same.

    This change was also backported to Jaybird 5.0.3.

  • Improvement: Statement.getResultSet no longer throws a SQLException with message “Only one result set at a time/statement” if the current result set has already been returned by executeQuery or a previous call to getResultSet (#762)

    Repeated calls to getResultSet will now return the current result set. As part of this change implementations of FirebirdStatement.getCurrentResultSet now simply returns getResultSet, and the getCurrentResultSet method has been deprecated for removal in Jaybird 7.

    This change was also backported to Jaybird 5.0.5.

  • Fixed: The implementation of Blob.getBytes(long, int) threw a SQLException if the remaining bytes of the blob were less than the requested number of bytes (#767)

    The JDBC API specifies “This byte array contains up to length consecutive bytes starting at position pos.”, so the implementation was changed to return up to length bytes, or the remaining actual blob length, whichever is shorter.

    The JDBC API does not specify what should happen if the requested position is beyond the end-of-blob. The modified implementation returns an empty array, but given this is unspecified behaviour, we reserve the option to change this in the future to throw an exception instead.

  • Fixed: CallableStatement.getXXX(String) could return value from wrong column (#771)

    This change was also backported to Jaybird 4.0.10 and Jaybird 5.0.3.

  • FBResultSetNotUpdatableException now extends SQLNonTransientException instead of FBSQLException.

  • Jaybird no longer throws any instances of FBSQLException.

    FBSQLException has been deprecated for removal in Jaybird 7.

  • Fixed: FBRowUpdater incorrectly considers result set with only partial PK updatable (#780)

    This change also improves performance of updateRow(), insertRow(), deleteRow() and refreshRow(). The best row identifier or RDB$DB_KEY were detected each time when calling updateRow(), insertRow(), deleteRow(), or refreshRow(). This has been improved so this detection is done once, and in a way that non-updatable result sets can now be downgraded to CONCUR_READ_ONLY instead of throwing an exception when performing the modification.

    This change was backported to Jaybird 5.0.4.

  • Improved detection of (non-)updatable result sets.

    If the best row identifier was not matched, but the result set contains RDB$DB_KEY, we will now consider the result set updatable. However, if the table in question has a primary key, and the columns missing from the result set are not generated, this may still fail when calling ResultSet.insertRow().

  • The user manager API (UserManager/FBUserManager and User/FBUser in package org.firebirdsql.management) has been deprecated (#782)

    We do not plan to remove this API at this time, but we recommend that you switch to using the SQL user management statements.

  • Fixed: Use of offset timezone names (e.g. +05:00) for sessionTimeZone would result in a warning being logged, and an incorrect conversion applied (in UTC instead of the offset) when using the legacy time types (#786)

    This change was also backported to Jaybird 5.0.4.

  • New feature: Added column JB_PK_INDEX_NAME to the result set of DatabaseMetaData.getPrimaryKeys with the name of the index backing the primary key (#791)

    Given this is a non-standard extension, it is advisable to retrieve this column by name, not by position.

  • Improvement: sessionTimeZone now also accepts the Java offset names (GMT[+-]HH:MM), which will be automatically converted to the Firebird compatible name ([+-]HH:MM).

  • New feature: ResultSetMetaData.isAutoIncrement(int) reports true for identity columns if Jaybird can identify the underlying table and column (#793)

    This feature was backported to Jaybird 5.0.5.

  • New feature: Boolean connection property extendedMetadata (default true) to disable querying of extended metadata for getPrecision(int) and isAutoIncrement(int) of ResultSetMetaData (#795)

    Disabling extended metadata may improve performance of these ResultSetMetaData methods in exchange for estimated precision information of NUMERIC and DECIMAL columns, and not being able to determine the auto-increment status of INTEGER, BIGINT or SMALLINT columns.

    This feature was backported to Jaybird 5.0.5.

  • Improvement: The FILTER_CONDITION of DatabaseMetaData.getIndexInfo is populated for Firebird 5.0 partial indices (#797)

    This improvement was backported to Jaybird 5.0.5.

  • Improvement: Added column JB_PK_INDEX_NAME and JB_FK_INDEX_NAME to the result set of to getImportedKeys, getExportedKeys and getCrossReference of DatabaseMetaData with the names of the index backing the primary key and foreign key (#798)

    Given this is a non-standard extension, it is advisable to retrieve these columns by name, not by position.

  • Change: TYPE_FORWARD_ONLY is no longer upgraded to TYPE_SCROLL_INSENSITIVE when requesting holdable result sets explicitly (holdability HOLD_CUSORS_OVER_COMMIT) or implicitly (defaultResultSetHoldable=true when not specifying holdability) (#802)

  • Improvement: isPoolable() on PreparedStatement and CallableStatement now returns the default of true — Statement returns false — as required by JDBC, and setPoolable records the value set to be returned by isPoolable (#803)

    To be clear, Jaybird does not provide statement pooling. This change is only about returning and recording the poolable information for JDBC compliance, so it can be used by — for example — connection pool implementations that provide statement pooling.

  • The state of Connection.setReadOnly(boolean) was not retained after calling Connection.setTransactionIsolation(int) or other method calls that changed the current transaction parameter buffer (#805)

  • Fixed: Exceptions during statement execution did not always complete the statement, which could delay transaction commit in auto-commit mode (#806)

    This fix was backported to Jaybird 5.0.6.

  • Fixed: ResultSet.isBeforeFirst() and ResultSet.isAfterLast() should always report false for an empty result set (#808)

  • Most public classes in package org.firebirdsql.jdbc have been annotated with @InternalApi to reflect that they are not actually part of the public API of Jaybird.

    Informally, these classes were already considered internal API, but given they are public, we now explicitly and formally document their status for clarity.

    Where possible, use the standard JDBC interfaces. If you need access to Firebird-specifics, unwrap or cast to the org.firebirdsql.jdbc.FirebirdXXX interfaces. Only cast to or otherwise access the concrete classes of org.firebirdsql.jdbc if you really have to, and keep in mind that their API — if not defined in java.sql or FirebirdXXX interfaces — may change in point releases.

    If you have a clear use-case that currently requires access to the concrete implementation classes, and you think it should be possible through a public API, please let us know on firebird-java or the https://github.com/FirebirdSQL/jaybird/issues.

  • Improvement: moved methods getExecutionPlan() and getExplainedExcutionPlan() from FirebirdPreparedStatement to FirebirdStatement, and clarified behaviour.

    We also fixed a potential NullPointerException in the implementation of these methods in PreparedStatement and CallableStatement.

    The methods getLastExecutionPlan() and getLastExplainedExecutionPlan() which were already defined in FirebirdStatement now have a default implementation that call getExecutionPlan() and getExplainedExecutionPlan(). These methods have been deprecated with the advice to use the new getters. For now, we have no plans to remove these methods in a future release.

  • Added dependency on org.jspecify:jspecify for nullability annotations.

    We are working on adding nullability information where applicable, but right now annotation of Jaybird is far from complete, and this will generally only be added when we touch a class for other reasons. The addition of these annotations is intended for making it easier for us to reason about the implementation, and get static analysis warnings about possible programming errors. Hopefully it will — in time — provide some benefits for users of Jaybird’s extension interfaces and “internal” APIs.

    If a type or its containing package is not annotated, consider return values and parameters of its methods nullable unless stated otherwise in the API documentation.

    In practice, this is an optional dependency, but Maven will pull it in by default, as that is recommended by JSpecify. If the JSpecify JAR is not included on the classpath or modulepath, Jaybird will still work.

  • DatabaseMetaData now reports ResultSet.TYPE_SCROLL_SENSITIVE as not supported, as it is always downgraded to TYPE_SCROLL_INSENSITIVE, and thus effectively not supported.

    This affects the return value of the methods supportsResultSetType(int), supportsResultSetConcurrency(int, int), ownUpdatesAreVisible(int), ownDeletesAreVisible(int), ownInsertsAreVisible(int).

  • Improvement: setObject/updateObject methods on PreparedStatement, CallableStatement and ResultSet with the int scaleOrLength parameter will now redirect to variants accepting a length of set/updateBinaryStream for InputStream and set/updateCharacterStream for Reader (#822)

  • New feature: Reporting of SQLWarnings can be disabled with connection property reportSQLWarnings (supported case-insensitive values: ALL (default), NONE) (#825)

    The default can be overridden globally using system property org.firebirdsql.jdbc.defaultReportSQLWarnings.

7.24. Potentially breaking changes

Jaybird 6 contains a number of changes that might break existing applications.

See also Compatibility changes for details.

7.25. Removal of deprecated classes and packages

8. Compatibility changes

Jaybird 6 introduces some changes in compatibility and announces future breaking changes.

The list might not be complete, if you notice a difference in behavior that is not listed, please report it as bug. It might have been a change we forgot to document, but it could just as well be an implementation bug.

8.1. Support for Firebird 2.5 dropped

Jaybird 6 has dropped support for Firebird 2.5 (see also jdp-2021-03: Drop Firebird 2.5 support).

By default, Jaybird 6 will only connect to Firebird 3.0 and higher. See also Unsupported protocol version disabled by default.

If the version 12 protocol (Firebird 2.5) is explicitly enabled, we expect the driver to remain functional, but chances are certain metadata — e.g. DatabaseMetaData — will break if we use features introduced in newer Firebird versions.

8.2. Unsupported protocol version disabled by default

The wire protocol versions for Firebird 2.5 and earlier are disabled by default to disallow connection for the pure Java protocol. Attempts to connect to Firebird 2.5 or earlier will result in error “connection rejected by remote interface” (335544421 or isc_connect_reject). You can use connection property enableProtocol=* or — for example — enableProtocol=10,11,12 to re-enable these protocols, or use the native protocol to connect instead.

As these protocols are not supported, it is possible things will break, especially for metadata — e.g. DatabaseMetaData if we use features introduced in newer Firebird versions.

8.3. Support for Java versions before Java 17 dropped

Jaybird 6 does not support Java versions before Java 17. You will need to upgrade to Java 17 or higher, or remain on Jaybird 5.

Jaybird 5 will serve as a form of “long-term support” for Java 8 and 11, with maintenance releases at least until the release of Jaybird 7.

8.4. Native and embedded require extra artifact

The main jaybird artifact no longer provides native and embedded support. Add the jaybird-native artifact if you use native or embedded (JDBC URL prefix jdbc:firebird[sql]:native: or jdbc:firebird[sql]:embedded:).

8.5. Support for jdbc:firebirdsql:oo: (OpenOffice/LibreOffice driver) dropped

The OOREMOTE protocol (JDBC URL prefix jdbc:firebird[sql]:oo:) has been removed in Jaybird 6.

The recommended replacement is to use LibreOffice and the builtin “Firebird External” connection option in LibreOffice Base, instead of the “JDBC” option with Jaybird on the classpath of LibreOffice.

8.6. Removed connection property timestampUsesLocalTimezone

The connection property timestampUsesLocalTimezone has been removed. The exact semantics and usage of this property were unclear. It was previously deprecated in Jaybird 5 for removal in Jaybird 6 or later.

Other code associated with this property was also removed.

8.7. Differences in client info property behavior

The rewritten client info properties implementation may result in the following incompatibilities:

  • setClientInfo(Properties) will now clear all known properties of USER_SESSION and — if not in auto-commit — USER_TRANSACTION which are not included in the Properties object; Jaybird 5 and earlier only set properties listed in the Properties object. The recommended approach is to use getClientInfo(), modify the returned Properties object (update values, add new properties, and remove properties which should be cleared), and call setClientInfo(Properties) with that object.

  • Initially, a connection only knows the properties ApplicationName, ClientUser and ClientHostname. Other properties are registered for the current connection when getting or setting properties.

  • getClientInfo(String) with a name without context will now always return the value from USER_SESSION; Jaybird 5 and earlier returned the value in USER_TRANSACTION and fell back to USER_SESSION if the property did not exist in USER_TRANSACTION. To get the value from USER_TRANSACTION, use <name>@USER_TRANSACTION.

  • If the property ApplicationName in USER_SESSION has no value, it falls back to CLIENT_PROCESS in SYSTEM (which reports the value of the processName connection property); Jaybird 5 and earlier reported null without falling back.

8.8. New Operation.Type value for async fetch

With the introduction of async fetch, the org.firebirdsql.gds.ng.monitor.Operation.Type enum has two new values added:

STATEMENT_ASYNC_FETCH_START

Start of async fetch. Covers sending of the fetch request. This operation is cancellable.

STATEMENT_ASYNC_FETCH_COMPLETE

Completion of async fetch. Covers processing the responses of the fetch request. This operation is not cancellable. Attempts to cancel this operation will throw an exception.

If you’re currently using the OperationAware interface to monitor and/or cancel fetches, make sure to also process STATEMENT_ASYNC_FETCH_START and/or STATEMENT_ASYNC_FETCH_COMPLETE as appropriate.

8.9. Changes in datetime conversions

The conversions of datetime values were overhauled to use the java.time types wherever possible.

This results in some minor differences:

  • getString(…​) on a TIME field will now render fractional seconds if available

  • setString(…​) on a TIME field now has seconds optional and accepts fractional seconds

  • setTime(…​) on a TIME field will not set sub-second values (previously this could vary with the millisecond value wrapped by java.sql.Time)

  • getString(…​) on a TIMESTAMP field will now render without .0 at the end if the value does not have fractional seconds (e.g. 2023-07-22 12:43:45 instead of 2023-07-22 12:43:45.0)

  • setString(…​) on a TIMESTAMP field now has seconds optional

  • setString(…​) on a TIMESTAMP field now also accepts ISO 8601 datetime strings (that is, with a T as a separator instead of a space, for example, 2023-07-22 12:43:45 and 2023-07-22T12:43:45 are now both accepted)

  • setDate(…​) on a TIMESTAMP field now sets time to 00:00:00 (previously this could vary with the millisecond value wrapped by java.sql.Date)

  • setTime(…​) on a TIMESTAMP field will now always set at 1970-01-01, and will not set sub-second values (previously this could vary with the millisecond value wrapped by java.sql.Time)

  • setTimestamp(…​) on a CHAR/VARCHAR/BLOB SUB_TYPE TEXT field will now set the value without .0 at the end if the value does not have fractional seconds (e.g. 2023-07-22 12:43:45 instead of 2023-07-22 12:43:45.0)

  • getTimestamp(…​) on a CHAR/VARCHAR/BLOB SUB_TYPE TEXT field will now also parse ISO 8601 datetime strings (that is, with a T as a separator instead of a space, for example, 2023-07-22 12:43:45 and 2023-07-22T12:43:45 are now both accepted), and seconds are now optional

  • getTime(…​) on a CHAR/VARCHAR/BLOB SUB_TYPE TEXT field will now parse values without seconds and values with fractional seconds. Though it can parse it, the resulting value will not include fractional seconds.

  • setDate(…​, Calendar) on a CHAR/VARCHAR/BLOB SUB_TYPE TEXT field will now use the Calendar to rebase the date, this can result in an off-by-one difference in the date compared to previous versions (depending on the time zone set on the Calendar)

  • getDate(…​, Calendar) on a CHAR/VARCHAR/BLOB SUB_TYPE TEXT field will now use the Calendar to rebase the date, this can result in an off-by-one difference in the date compared to previous versions (depending on the time zone set on the Calendar)

  • The TypeConversionException thrown by getDate(…​), getTime(…​) and getTimestamp(…​) on unsupported types may now report java.time.LocalDate, java.time.LocalTime or java.time.LocalDateTime as the type in its error message instead of java.sql.Date, java.sql.Time, or java.sql.Timestamp

8.10. Execution of COMMIT and ROLLBACK rejected by default

Attempts to prepare or execute COMMIT or ROLLBACK (without RETAIN or a savepoint) will now fail by default. In previous versions, executing these statements would work, but leave the connection in an unusable state. The exact error will — generally — be one of the following:

337248313

Execution of COMMIT statement is not allowed, use Connection.commit(), or set connection property allowTxStmts to true

337248314

Execution of ROLLBACK statement is not allowed, use Connection.rollback(), or set connection property allowTxStmts to true

337248319

Using addBatch with a transaction management statement is not supported

337248320

Using prepareCall with a transaction management statement is not supported

In the case of the execute, executeUpdate or executeLargeUpdate methods of Statement, or the prepareStatement methods of Connection, this can be resolved by allowing the execution with connection property allowTxStmts set to true.

In the case of Statement.executeQuery(String) and PreparedStatement.executeQuery(), you will need to switch to using one of the other execute, executeUpdate or executeLargeUpdate methods.

It is not possible to use the prepareCall methods of Connection with these statements. In previous versions of Jaybird, subsequent execution wouldn’t work either — or attempt to execute stored procedures called COMMIT or ROLLBACK, but it is now rejected early in the prepareCall methods of Connection. Switch to using prepareStatement.

Additionally, using Statement.addBatch(String) and PreparedStatement.addBatch() will not work with these statements. Switch to using one of the normal execute methods.

8.11. Forward-only holdable result sets no longer upgraded to scroll-insensitive

Jaybird no longer upgrades TYPE_FORWARD_ONLY holdable result sets to TYPE_SCROLL_INSENSITIVE. As a result, for these result sets, only the next() navigation method is allowed, and other navigation methods will throw an SQLException, just like a forward-only non-holdable result set.

In previous versions this upgrade occurred when creating a TYPE_FORWARD_ONLY result set, either explicitly when asking for holdability HOLD_CURSORS_OVER_COMMIT, or implicitly when defaultResultsetHoldable=true (or defaultHoldable=true or result_set_holdable=true) and no holdability was specified.

If you relied on this type upgrade to access navigation methods other than next(), you will need to explicitly ask for a TYPE_SCROLL_INSENSITIVE result set.

8.12. Read-only behaviour of connections

In previous versions of Jaybird the read-only state of a connection was not retained if the transaction parameter buffer was replaced, for example by calls to setTransactionIsolation(int).

Now this has been corrected, it is possible that your code unexpectedly throws an exception with message “attempted update during read-only transaction [SQLState:42000, ISC error code:335544361]” (error isc_read_only_trans).

You need to make sure to call setReadOnly(false) if the connection was previously marked read-only. If you’re using a connection pool, you need to ensure it properly resets the read-only state of the connection when checking in or checking out the connection. For example, both Apache DBCP and Apache Tomcat connection pools requires the defaultReadOnly property to be set (i.e. to false), otherwise it will not reset the read-only state.

If overridden transaction mappings are used, and the default isolation level has isc_tpb_read, the connection will be marked as read-only. As a result, switching isolation levels will now also result in read-only transactions, even if the mapping of the other isolation level is defined with isc_tpb_write. You will need to explicitly call setReadOnly(false), or — better yet — do not override transaction mappings with a isc_tpb_read, but always use isc_tpb_write, and control read-only state only through setReadOnly.

8.13. ResultSet in auto-commit no longer closed after last row

8.14. Behavioural changes for updatable scrollable ResultSet

8.15. Removal of classes, packages and methods without deprecation

Below list of removals may look daunting, but if you use Jaybird only as a JDBC driver, through the JDBC API, you’re likely unaffected. Although we list them as removed without deprecation, some were marked as deprecated retroactively in Jaybird 5.0.3 or later.

This section does not include all changes to packages or classes considered internal API.

8.15.1. Removal of packages without deprecation

The following packages have been removed in Jaybird 6 without deprecation:

  • org.firebirdsql.logging; there is no replacement

Due to modularization, the following packages are no longer accessible when Jaybird is used from the modulepath:

jaybird dependency
  • org.firebirdsql.gds.ng.dbcrypt.simple

  • org.firebirdsql.gds.ng.tz

  • org.firebirdsql.gds.ng.wire.auth.legacy

  • org.firebirdsql.gds.ng.wire.auth.srp

  • org.firebirdsql.gds.ng.wire.crypt.arc4

  • org.firebirdsql.gds.ng.wire.crypt.chacha

  • org.firebirdsql.gds.ng.wire.versionNN (with NN, is 10, 11, 12, 13, 15, 16 and 18)

  • org.firebirdsql.jaybird

  • org.firebirdsql.jaybird.parser

  • org.firebirdsql.jaybird.props.internal

  • org.firebirdsql.jaybird.util

  • org.firebirdsql.jdbc.escape

  • org.firebirdsql.jdbc.meta

jaybird-native dependency
  • org.firebirdsql.gds.impl.jni

  • org.firebirdsql.gds.ng.jna

  • org.firebirdsql.jna.embedded

  • org.firebirdsql.jna.fbclient

8.15.2. Removal of methods without deprecation

The following methods have been removed in Jaybird 6 without deprecation:

  • FBConnection

    • prepareMetaDataStatement(String, int, int); use prepareStatement(String, int, int, int, boolean, boolean)

    • getStatementListener(); there is no replacement

    • inTransaction(); there is no replacement

  • JaybirdSystemProperties

    • isForceConsoleLogger(); there is no replacement

    • isDisableLogging(); there is no replacement

    • getLoggerImplementation(); there is no replacement

  • FBCallableStatement

    • findOutParameter(String) (protected); use getAndAssertSingletonResultSet().findColumn(paramName); carefully check if that is the correct usage (the method was removed because the old usage within Jaybird resulted in mapping the wrong column)

  • FBProcedureCall

    • mapOutParamIndexToPosition(int, boolean); use mapOutParamIndexToPosition(int) (equivalent to passing true), there is no replacement for the false behaviour

8.15.3. Removal of classes without deprecation

The following classes have been removed in Jaybird 6 without deprecation:

  • FbLocalDatabaseFactory — unused since removal of LOCAL protocol implementation in Jaybird 5.

  • DatatypeCoder.RawDateTimeStruct (semi-internal API) — use one of the java.time types (LocalDateTime, LocalDate or LocalTime). Though this class was publicly accessible through ResultSet.getObject/updateObject and PreparedStatement.setObject, it is internal API, and we expect it is unlikely to be actually used in user code.

  • FBDriverConsistencyCheckException — unused since the changes to client info properties.

The following classes are no longer accessible in Jaybird 6:

  • RowValueBuilder is now package private

The following classes are no longer extensible in Jaybird 6 as they are now sealed or final:

  • FBPooledConnection

    • Visibility was also reduced to package-private

  • FBXAConnection

    • Visibility was also reduced to package-private

  • PooledConnectionHandler

    • Class was already package-private

  • XAConnectionHandler

    • Visibility was also reduced to package-private

  • StoredProcedureMetaDataFactory

    • Visibility was also reduced to package-private

8.15.4. Removal of constants without deprecation

The following constants have been removed in Jaybird 6 without deprecation:

  • JaybirdSystemProperties

    • FORCE_CONSOLE_LOGGER_PROP; there is no replacement

    • DISABLE_LOGGING_PROP; there is no replacement

    • LOGGER_IMPLEMENTATION_PROP; there is no replacement

  • SQLStateConstants

    • SQL_STATE_INVALID_CONN_ATTR (01S00) — it was unused; there is no replacement

    • SQL_STATE_INVALID_COLUMN (HY002); replaced by SQL_STATE_INVALID_DESC_FIELD_ID (HY091)

    • SQL_STATE_INVALID_ARG_VALUE (HY009); used with wrong meaning, replaced by multiple other constants (SQL_STATE_INVALID_USE_NULL (HY009, same value), SQL_STATE_ATT_CANNOT_SET_NOW (HY011) , SQL_STATE_INVALID_ATTR_VALUE (HY024), SQL_STATE_INVALID_STRING_LENGTH (HY090))

    • SQL_STATE_INVALID_TRANSACTION_STATE (25S01) — it was unused; there is no replacement

    • SQL_STATE_TRANSACTION_ACTIVE (25S02) — it was unused; there is no replacement

    • SQL_STATE_TRANSACTION_ROLLED_BACK (25S03) — it was unused; there is no replacement

    • SQL_STATE_CONNECTION_FAILURE_IN_TX (08007) — it was unused; there is no replacement

    • SQL_STATE_COMM_LINK_FAILURE (08S01) — it was unused; there is no replacement

  • FBProcedureCall

    • OLD_CALLABLE_STATEMENT_COMPATIBILITY; there is no replacement

8.16. Removal of deprecated classes, packages and methods

Below list of removals may look daunting, but if you use Jaybird only as a JDBC driver, through the JDBC API, you’re likely unaffected.

8.16.1. Removal of deprecated packages

The following packages have been removed in Jaybird 6:

  • org.firebirdsql.gds.impl.oo

  • org.firebirdsql.jdbc.oo

8.16.2. Removal of deprecated methods

The following methods have been removed in Jaybird 6:

  • FirebirdConnectionProperties
    Changes to the FirebirdConnectionProperties interface affect the data source implementations in org.firebirdsql.ds, and FBManagedConnectionFactory.

    • getDatabase() and all its implementations; use DatabaseConnectionProperties.getDatabaseName()

    • setDatabase(String) and all its implementations; use DatabaseConnectionProperties.setDatabaseName(String)

    • getNonStandardProperty(String) and all its implementations; use BaseProperties.getProperty(String)

    • setNonStandardProperty(String,String) and all its implementations; use BaseProperties.setProperty(String,String)

    • getBuffersNumber and all its implementations; use DatabaseConnectionProperties.getPageCacheSize

    • setBuffersNumber and all its implementations; use DatabaseConnectionProperties.setPageCacheSize

  • IConnectionProperties

    • short getConnectionDialect() and all its implementations; use int DatabaseConnectionProperties.getSqlDialect()

    • setConnectionDialect(short), and all its implementations; use DatabaseConnectionProperties.setSqlDialect(int)

  • FBSimpleDataSource.get/setBlobBufferLength; use get/setBlobBufferSize

  • EventManager

    • get/setHost; use get/setServerName

    • get/setPort; use get/setPortNumber

    • get/setDatabase; use get/setDatabaseName

  • GDSFactory.getJdbcUrl(GDSType, String); use GDSFactory.getJdbcUrl(GDSType, DatabaseConnectionProperties)

  • FBManagedConnection.getDatabase(); there is no direct replacement, but the information can be obtained from the connection properties

  • GDSHelper.getIscEncoding(); there is no replacement

  • FirebirdConnection.getIscEncoding; there is no replacement

  • FBBlob

    • constructors FBBlob(GDSHelper) and FBBlob(GDSHelper, FBObjectListener.BlobListener); use FBBlob(GDSHelper, FBObjectListener.BlobListener, Config)

    • constructors FBBlob(GDSHelper c, long blobId) and FBBlob(GDSHelper c, long blobId, FBObjectListener.BlobListener blobListener); use FBBlob(GDSHelper, long, FBObjectListener.BlobListener, Config)

  • DatabaseConnectionProperties

    • isTimestampUsesLocalTimezone/setTimestampUsesLocalTimezone(boolean); there is no replacement

  • FBSQLException

    • constructor FBSQLException(String, SQLException); use FBSQLException(String) or FBSQLException(String, String) followed by setNextException(SQLException)

    • getInternalException(); use getCause()

  • FBServiceManager

    • executeServicesOperation(ServiceRequestBuffer); use executeServicesOperation(FbService, ServiceRequestBuffer)

  • FirebirdDriver (and FBDriver)

    • newConnectionProperties() — was not previously deprecated, see next method

    • connect(FirebirdConnectionProperties); use FBSimpleDataSource for programmatic access to connection properties and connection creation

8.16.3. Removal of deprecated classes

The following classes have been removed in Jaybird 6:

  • org.firebirdsql.gds.ng.listeners.DefaultDatabaseListener; implementing DatabaseListener is now sufficient as all methods in the interface now have a default implementation that does nothing

  • org.firebirdsql.gds.ng.listeners.DefaultStatementListener; implementing StatementListener is now sufficient as all methods in the interface now have a default implementation that does nothing

  • org.firebirdsql.jdbc.FBConnectionDefaults; its replacement, org.firebirdsql.jaybird.props.PropertyConstants, is considered internal API

8.16.4. Removal of deprecated constants

The following constants have been removed in Jaybird 6:

  • All public String constants in FBDriver; the replacement for most constants can be found in org.firebirdsql.jaybird.props.PropertyNames, though some will be removed without replacement

  • ISCConstants.isc_dpb_* that are DPB items; the replacement is the constant with the same name in org.firebirdsql.jaybird.fb.constants.DpbItems

  • ISCConstants.isc_tpb_* that are TPB items; the replacement is the constant with the same name in org.firebirdsql.jaybird.fb.constants.TpbItems

  • ISCConstants.isc_spb_* that are SPB items; the replacement is the constant with the same name in org.firebirdsql.jaybird.fb.constants.SpbItems

  • ISCConstants.isc_bpb_* that are BPB items; the replacement is the constant with the same name in org.firebirdsql.jaybird.fb.constants.BpbItems

  • ISCConstants.isc_bpb_type_segmented and ISCConstants.isc_bpb_type_stream; the replacement is the constant with the same name in org.firebirdsql.jaybird.fb.constants.BpbItems.TypeValues

  • All constants in DatabaseParameterBuffer; use the equivalent constant from org.firebirdsql.jaybird.fb.constants.DpbItems

  • All constants in TransactionParameterBuffer; use the equivalent constant from org.firebirdsql.jaybird.fb.constants.TpbItems

  • All constants in ServiceParameterBuffer; use the equivalent constant from org.firebirdsql.jaybird.fb.constants.SpbItems

  • All constants in BlobParameterBuffer; use the equivalent constant from org.firebirdsql.jaybird.fb.constants.BpbItems and org.firebirdsql.jaybird.fb.constants.BpbItems.TypeValues

  • All TPB_* constants in FirebirdConnection; use the equivalent constant from org.firebirdsql.jaybird.fb.constants.TpbItems

  • All public String constants in org.firebirdsql.jdbc.FBConnectionProperties; the replacement for most constants can be found in org.firebirdsql.jaybird.props.PropertyNames, though some will be removed without replacement

  • GDSHelper.DEFAULT_BLOB_BUFFER_SIZE; its replacement, org.firebirdsql.jaybird.props.PropertyConstants.DEFAULT_BLOB_BUFFER_SIZE, is considered internal API

  • All constants in IConnectionProperties; use the equivalent constant from org.firebirdsql.jaybird.props.PropertyConstants, though this class is considered internal API

  • All constants in IServiceProperties; use the equivalent constant from org.firebirdsql.jaybird.props.PropertyConstants, though this class is considered internal API

  • PropertyNames.timestampUsesLocalTimezone; there is no replacement

8.17. Breaking changes internal API

The following breaking changes were made to the internal API, like the GDS-ng API in org.firebirdsql.gds.ng and sub-packages. These changes are primarily interesting for implementers of custom GDS-ng implementations or forks of Jaybird, or people using these low-level APIs directly.

Only changes we think are relevant to driver implementers or (internal) API users are documented. This means there may be undocumented changes to internal API. If you are confronted with such a change, let us know on firebird-java, so we can take this into account when documenting future changes.

  • FbWireDatabase

    • enqueueDeferredAction(DeferredAction) now throws SQLException to be able to handle exceptions for sync actions if there are a lot of deferred packets

  • FbWireOperations

    • enqueueDeferredAction(DeferredAction) now throws SQLException (see also FbWireDatabase above)

  • AbstractFbStatement

    • setCursorName(String) is now final; subclasses need to implement setCursorNameImpl(String) to provide the actual implementation. These implementations do not need to take out the lock, nor notify the exception listener dispatcher, as that is already handled in the final setCursorName(String) method.

    • The most recent cursor name is now accessible with protected String getCursorName(). Its value is reset to null on each prepare.

  • AbstractFbWireStatement

    • close() is now final

    • wrapDeferredResponse received an extra parameter, boolean requiresSync. This parameter signals if the deferred response requires some form of synchronization action to instruct the server to send the response. When in doubt, use false to communicate that no such synchronization is required.

  • JnaDatabase

    • getEncodingDefinition was removed; there is no replacement

  • DeferredAction

    • wrapDeferredResponse received an extra parameter, boolean requiresSync. This parameter signals if the deferred response requires some form of synchronization action to instruct the server to send the response. When in doubt, use false to communicate that no such synchronization is required.

  • AsynchronousChannelListener.Event was converted to a record, so it is now final, and its getters (getEventId() and getEventCount()) have been replaced by accessor methods (eventId() and eventCount())

  • DbAttachInfo was converted to a record, so its getters (getServerName(), getPortNumber() and getAttachObjectName()) have been replaced by accessor methods (serverName(), portNumber(), attachObjectName())

  • XdrInputStream

    • skipPadding return type was changed to void as the return value is never used in Jaybird code

    • skipFully was removed; use standard Java InputStream.skipNBytes instead

    • readShort was removed as it was unused

  • The no-arg constructor of FBXAException was removed

  • FBResultSet

    • close(boolean) was removed; use close(boolean, CompletionReason)

  • FBProcedureCall is no longer cloneable; use FBProcedureCall.copyOf(FBProcedureCall)

  • UnixCrypt was replaced by LegacyHash, which only performs the password hash specific to Firebird legacy authentication

  • GDSFactoryPlugin.getDatabasePath(String, Integer, String) and getDatabasePath(String) no longer throw GDSException, but instead throw SQLException

  • GDSFactory.getDatabasePath(…​) no longer throw GDSException, but instead throw SQLException

  • GDSServerVersionException no longer extends GDSException, but instead extends SQLNonTransientException

  • GDSException was significantly modified and deprecated for future removal. Most of its implementation was removed, and it now extends SQLException. Only the constructors GDSException(int), GDSException(int, Throwable) and GDSException(String) were retained. All other constructors and methods have been removed.

  • WireGDSFactoryPlugin, NativeGDSFactoryPlugin and EmbeddedGDSFactoryPlugin are now final

  • FbEmbeddedDatabaseFactory is now final

  • FbClientDatabaseFactory and FbEmbeddedDatabaseFactory now have a private constructor; use their static getInstance() method to obtain an instance

  • DefaultDatatypeCoder.intToBytes(int) was removed; use encodeInt(int)

  • ChaChaEncryptionPlugin and ChaChaEncryptionPluginSpi are now final

  • CryptSessionConfig, the JavaBeans-style accessors have been replaced with record-style accessors:

    • getEncryptionIdentifier()encryptionIdentifier()

    • getEncryptKey()encryptKey()

    • getDecryptKey()decryptKey()

    • getSpecificData()specificData()

  • EncryptionIdentifier, some JavaBeans-style accessors have been replaced with record-style accessors:

    • getType()type()

    • getPluginName()pluginName()

  • KnownServerKey.PluginSpecificData, the JavaBeans-style accessors have been replaced with record-style accessors:

    • getEncryptionIdentifier()encryptionIdentifier()

    • getSpecificData()specificData()

  • EncryptionPlugin and EncryptionPluginSpi, the JavaBeans-style accessor has been replaced with a record-style accessor:

    • getEncryptionIdentifier()encryptionIdentifier()

  • StringArgument

    • constructor StringArgument(int, ArgumentType, String); use StringArgument(int, ArgumentType, String, Encoding)

  • FBConnection

    • checkClientInfoSupport() was removed; there is no replacement

  • IEncodingFactory

    • <T extends DatatypeCoder> T getOrCreateDatatypeCoder(Class<T>) was removed; its replacements is <T extends DatatypeCoder> T getOrCreateDatatypeCoder(Class<T>, Function<IEncodingFactory, T>) where the function is a factory for the desired DatatypeCoder instance if it doesn’t already exist.

  • The following classes in org.firebirdsql.util were moved to org.firebirdsql.jaybird.util. This package is internal API only, and not exported from the module.

    • ByteArrayHelper

    • ExceptionHelper

    • IOUtils

    • Primitives

    • ReflectionHelper

    • SQLExceptionChainBuilder

    • StringUtils

  • DbMetadataMediator was moved to package org.firebirdsql.jdbc for module accessibility reasons.

  • DatatypeCoder

    • encodeTimestamp(Timestamp, Calendar, boolean) was removed; there is no replacement

    • decodeTimestamp(Timestamp, Calendar, boolean) was removed; there is no replacement

    • encodeTimestampCalendar(Timestamp, Calendar) was removed; use encodeLocalDateTime(LocalDateTime)

    • decodeTimestampCalendar(byte[], Calendar) was removed; use decodeLocalDateTime(byte[])

    • encodeTimestampRaw(DatatypeCoder.RawDateTimeStruct) was removed; use encodeLocalDateTime(LocalDateTime)

    • decodeTimestampRaw(byte[]) was removed; use decodeLocalDateTime(byte[])

    • encodeTime(Time, Calendar, boolean) was removed; there is no replacement

    • decodeTime(Time, Calendar, boolean) was removed; there is no replacement

    • encodeTimeCalendar(Time, Calendar) was removed; use encodeLocalTime(LocalTime)

    • decodeTimeCalendar(byte[], Calendar) was removed; use decodeLocalTime(byte[])

    • encodeTimeRaw(DatatypeCoder.RawDateTimeStruct) was removed; use encodeLocalTime(LocalTime)

    • decodeTimeRaw(byte[]) was removed; use decodeLocalTime(byte[])

    • encodeDate(Date, Calendar) was removed; there is no replacement

    • decodeDate(Date, Calendar) was removed; there is no replacement

    • encodeDateCalendar(Date, Calendar) was removed; use encodeLocalDate(LocalDate)

    • decodeDateCalendar(byte[], Calendar) was removed; use decodeLocalDate(byte[])

    • encodeDateRaw(DatatypeCoder.RawDateTimeStruct) was removed; use encodeLocalDate(LocalDate)

    • decodeDateRaw(byte[]) was removed; use decodeLocalDate(byte[])

  • FetchResponse was converted to a record, and its getters (getStatus() and getCount()) have been replaced by accessor methods (status() and count())

  • GenericResponse was converted to a record, and its getters (getObjectHandle(), getBlobId(), getData() and exception()) have been replaced by accessor methods (objectHandle(), blobId(), data() and exception())

  • SQLResponse was converted to a record, and its getter (getCount()) has been replaced by an accessor method (count())

  • SQLExceptionChainBuilder

    • Moved to package org.firebirdsql.jaybird.util; this package is internal API only, and not exported from the module (see also earlier)

    • The generics <E extends SQLException> were removed from this class

      • append and addFirst now always expect SQLException

      • getException() now always returns SQLException

    • Constructor SQLExceptionChainBuilder(SQLException) was removed, as in practice this was never used; replacement is new SQLExceptionChainBuilder().append(exception)

  • FBTpb was removed, and its usages were replaced with TransactionParameterBuffer

  • FBTpbMapper no longer implements Cloneable, use FBTpbMapper.copyOf(FBTpbMapper) instead

  • ParameterBuffer now extends Serializable, as all implementations are serializable, and some usages expect serializable behaviour even when the interfaces were used (though in practice, these objects are hardly ever serialized)

  • FBManagedConnection

    • setReadOnly(boolean) was renamed to setTpbReadOnly(boolean) to reflect what it actually does

    • isReadOnly() was renamed to isTpbReadOnly() to reflect what it actually does

  • FBObjectListener.FetcherListener

    • fetcherClosed(FBFetcher) was removed

    • allRowsFetched(FBFetcher) was removed

  • FBObjectListener.ResultSetListener

    • allRowsFetched(ResultSet) was removed

8.18. Unlikely breaking changes

The following changes might cause issues, though we think this is unlikely:

8.18.1. Removal of finalization

With the removal of finalization, the replacement cleanup has been simplified, and in some cases left out entirely.

Possible effects include:

  • If a close/cleanup is performed by the Cleaner, listeners will not get notified. Given it is unlikely there will not be strong reference to an object if something is still interested in its listener events, we think this is acceptable.

  • The closing of a pure Java connection which was not explicitly closed is now simply a socket close handled by the cleanup action of the socket itself. Server-side this may result in delayed cleanup of a connection and its resources, and occurrences of “connection reset by peer” (e.g. error 10054 on Windows, error 104 on Linux). If you see an increase of these errors, we recommend you hunt for connection leaks in your application.

8.18.2. Conversion from double to BigDecimal

Conversions from double to java.math.BigDecimal now always use BigDecimal.valueOf(double). Previously, a combination of new BigDecimal(double) and BigDecimal.valueOf(double) was used.

This change may result in minor differences in precision or rounding of values.

8.19. Breaking changes for Jaybird 7

With Jaybird 7 the following breaking changes will be introduced.

8.19.1. Removal of deprecated classes, packages and methods

Removal of deprecated methods

The following methods will be removed in Jaybird 7:

  • GDSFactoryPlugin (semi-internal API)

    • getTypeAliases() — use getTypeAliasList()

    • getSupportedProtocols — use getSupportedProtocolList()

  • GDSHelper (internal API)

    • startTransaction(TransactionParameterBuffer) — use FbDatabase.startTransaction(TransactionParameterBuffer) followed by GDSHelper.setCurrentTransaction(FbTransaction)

  • FirebirdStatement

    • getCurrentResultSet() — use getResultSet()

  • SqlCountHolder (internal API)

    • getLongUpdateCount() — use updateCount()

    • getLongDeleteCount() — use deleteCount()

    • getLongInsertCount() — use insertCount()

    • getLongSelectCount() — use selectCount()

Removal of deprecated classes

The following classes have been deprecated and will be removed in Jaybird 7:

  • GDSException; use SQLException or one of its (normal) subclasses. Previous versions of GDSFactoryPlugin declared throws GDSException for some methods, but now throws SQLException. To retain some semblance of backwards-compatibility, this class was retrofitted to extend SQLException.

  • FBSQLException; use SQLException

8.19.2. Removal of deprecated constants

The following constants have been deprecated and will be removed in Jaybird 7:

  • ISCConstants

    • isc_isc_sql_dialect_conflict_num (was already deprecated, now for removal); use isc_sql_dialect_conflict_num

    • isc_err_max; there is no replacement

  • QuoteStrategy — due to addition of methods appendLiteral and quoteLiteral the original enum names no longer made sense

    • NO_QUOTES — use DIALECT_1

    • QUOTES — use DIALECT_3

9. Compatibility notes

9.1. Type 2 (native) and embedded driver

Since Jaybird 6, the native and embedded part of the driver has been moved to a separate artifact, jaybird-native. The Jaybird Native GDS Factory plugin uses JNA to access the client library. If you want to use the Type 2 driver, or Firebird embedded, then you need to include jaybird-native-6.0.0-beta-1 and jna-jpms-5.15.0.jar on the classpath.

When using Maven, you need to specify the dependency on jaybird-native:

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>jaybird-native</artifactId>
    <version>6.0.0-beta-1</version>
</dependency>

The fbclient.dll, fbembed.dll, libfbclient.so, or libfbembed.so need to be on the path, or the location needs to be specified in the system property jna.library.path (as an absolute or relative path to the directory/directories containing the library file(s)).

For Windows and Linux, you can add the org.firebirdsql.jdbc:fbclient dependency on your classpath to provide the native libraries for the native and local protocol. Be aware that this dependency does not support embedded.

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>fbclient</artifactId>
    <version>5.0.1.1</artifactId>
</dependency>

For more information about this library, see https://github.com/mrotteveel/jaybird-fbclient.

In the future we may provide JARs with the embedded libraries of a specific Firebird version.


1. since Firebird 3.0.2, version 13 for 3.0.0 and 3.0.1
2. Jaybird has no protocol 14 implementation
3. Jaybird has no protocol 17 implementation
4. For get the maximum segment size is actually the maximum buffer size to receive one or more segments which are prefixed with two bytes for the length