Jaybird Manual
Jaybird Manual
Programmer’s Manual
Roman Rokytskyy, Mark Rotteveel
Table of Contents
1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1. This manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3. Jaybird Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.4. Jaybird Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5. Quality Assurance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.6. Useful resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.7. Contributing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
User Manual. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2. Obtaining a connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1. Obtaining connection java.sql.DriverManager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2. Driver types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3. Connection Pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4. The javax.sql.DataSource implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.5. The javax.sql.ConnectionPoolDataSource implementation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.6. The javax.sql.XADataSource implementation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3. Handling exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1. Working with exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2. Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3. java.sql.SQLException in Jaybird . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.4. SQL states . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.5. Useful Firebird error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4. Executing statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.1. The java.sql.Statement interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2. Statement behind the scenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.3. The java.sql.PreparedStatement interface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.4. The java.sql.CallableStatement interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.5. Batch Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.6. Escape Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5. Working with result sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.1. ResultSet properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.2. ResultSet manipulation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6. Using transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.1. JDBC transactions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.2. Auto-commit mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
6.3. Read-only Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.4. Transaction Isolation Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.5. Savepoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.6. Transaction Parameter Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.7. Table Reservation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7. Working with Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.1. ServiceManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.2. Backup and restore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.3. User management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
7.4. Database maintenance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
7.5. Database statistics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
8. Working with Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
8.1. Database events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
8.2. Posting events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
8.3. Subscribing to events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Reference Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
9. Connection reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
9.1. Authentication plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
9.2. Wire encryption support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
9.3. Wire compression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
9.4. Database encryption support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
9.5. Default holdable result sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
9.6. Firebird auto commit mode (experimental) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
9.7. Process information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
9.8. Data type bind support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
10. Statement reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
10.1. Generated keys retrieval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
10.2. Connection property ignoreProcedureType . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
11. General. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
11.1. Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
12. Datatype reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
12.1. Binary types BINARY/VARBINARY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
12.2. Type BOOLEAN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
12.3. Date/time types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
12.4. Decimal floating point type DECFLOAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
12.5. Exact numeric types DECIMAL/NUMERIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
12.6. Type INT128 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Appendices. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Appendix A: Extended connection properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
A.1. Authentication and security properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
A.2. Other properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
A.3. Transaction isolation levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Appendix B: System properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
B.1. Logging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
B.2. Process information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
B.3. Character set defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
B.4. Other properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
B.5. Useful Java system properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Appendix C: Data Type Conversion Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
C.1. Mapping between JDBC, Firebird and Java Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
C.2. Data Type Conversions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Appendix D: Connection Pool Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
D.1. Standard JDBC Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
D.2. Pool Properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
D.3. Runtime Pool Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
D.4. Firebird-specific Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
D.5. Non-standard parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Appendix E: Character Encodings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
E.1. Encodings Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
E.2. Encodings in Java. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
E.3. Available Encodings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Appendix F: Supported JDBC Scalar Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
F.1. Numeric Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
F.2. String Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
F.3. Time and Date Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
F.4. System Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
F.5. Conversion Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Appendix G: Jaybird versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
G.1. Jaybird 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
G.2. Jaybird 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
G.3. Jaybird 2.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Appendix H: License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Chapter 1. Introduction
Chapter 1. Introduction
Jaybird is a JCA/JDBC driver suite to connect to the Firebird database server.
This driver is based on both the JCA standard for application server connections to enterprise
information systems and the well-known JDBC standard. The JCA standard specifies an architecture
in which an application server can cooperate with a driver so that the application server manages
transactions, security, and resource pooling, and the driver supplies only the connection
functionality.
Jaybird is a driver that provides both Type 4 (pure Java) and Type 2 (native binding) support. The
type 2 driver includes support for Firebird Embedded.
New or removed features are tagged with the version that introduced a feature (eg Since: Jaybird 3)
or removed feature (eg Removed in: Jaybird 3). This tagging is only done for features introduced
(or removed) in Jaybird 2.2 or later, or in Firebird 3 or later, and for features available in Java/JDBC
versions 8/4.2 or later.
This manual may include documentation of features of — possibly unreleased — Jaybird versions
later than 4 to simplify manual maintenance and versioning.
1.2. History
When Borland released an open-source version of the InterBase RDBMS, it included sources for a
[1]
type 3 JDBC driver called InterClient. However due to some inherent limitations of the InterBase
(and later Firebird) client library, it was decided that the type 3 driver was a dead end. Instead, the
Firebird team decided to develop a pure Java implementation of the wire protocol. This
implementation became the basis for Jaybird, a pure Java driver for Firebird relational database.
• The GDS layer represents a Java translation of the Firebird API. It is represented by a number of
interfaces and classes from the org.firebirdsql.gds package (and sub-packages).
This API is implemented by a number of plugins that provide the pure java, native, local, and
embedded implementations of the driver.
• The JCA layer represents the heart of the driver. Here all connection and transaction
management happens. Additionally this layer adapts the GDS API and proxies the calls to the
GDS implementation.
1
Chapter 1. Introduction
In addition, the Services API allows you to manage the database and the server itself. The Manager
component represents a JMX compatible implementation that utilizes the Services API. Currently
only calls to create and drop database are available in the Manager component, other class provide
features for database backup/restore, user management, statistics gathering, etc.
1.4.1. Maven
Alternatively, you can use maven to automatically download Jaybird and its dependencies.
Groupid: org.firebirdsql.jdbc,
Artifactid: jaybird,
Version: 4.0.0.<java> (where <java> is java7, java8 or java11)
For example:
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird</artifactId>
<version>4.0.0.java11</version>
</dependency>
If your application is deployed to a Java EE application server, you will need to exclude the
javax.resource:connector-api dependency, and add it as a provided dependency:
2
Chapter 1. Introduction
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird</artifactId>
<version>4.0.0.java11</version>
<exclusions>
<exclusion>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
<version>1.5</version>
<scope>provided</scope>
</dependency>
If you want to use Type 2 support (native, local or embedded), you need to explicitly include JNA
5.5.0 as a dependency:
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.5.0</version>
</dependency>
We plan to make native and embedded support a separate library in future releases, and provide
Firebird client libraries as Maven dependencies as well.
3
Chapter 1. Introduction
1.6.2. Firebird
General information about the Firebird database is available from the Firebird web site
(https://www.firebirdsql.org/).
For information about using SQL in Firebird, see the Firebird 2.5 Language Reference
[https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25.html] and
other documents available from the Reference Manuals [https://www.firebirdsql.org/en/reference-
manuals/] section of the Firebird web site.
This is a place where the community shares information about different aspects of Jaybird
usage, configuration examples for different applications/servers, tips and tricks, FAQ, etc.
• On Stack Overflow [https://stackoverflow.com/], please tag your questions with jaybird and firebird
Please make sure to familiarize yourself with the rules and expectations of Stack Overflow
before asking, see Stack Overflow Tour [https://stackoverflow.com/tour] and Help Center: Asking
[https://stackoverflow.com/help/asking]
1.7. Contributing
There are several ways you can contribute to Jaybird or Firebird in general:
• Become a developer (for Jaybird contact us on firebird-java, for Firebird in general, use the
Firebird-devel mailing list)
4
Chapter 1. Introduction
You can report bugs in the Firebird bug tracker, project "Jaybird JCA/JDBC Driver"
[http://tracker.firebirdsql.org/browse/JDBC]
When reporting bugs, please provide a minimal, but complete reproduction, including databases
and source code to reproduce the problem. Patches to fix bugs are also appreciated. Make sure the
patch is against a recent master version of the code. You can also fork the jaybird repository and
create pull requests.
[1] For those interested in software archaeology, you can find the open sourced Interclient sources archived on https://github.com/
FirebirdSQL/x-cvs-interclient
5
Chapter 1. Introduction
6
User Manual
7
8
Chapter 2. Obtaining a connection
There is also support to specify additional connection parameters, like user name and password.
jdbc:firebirdsql://localhost:3050/c:/database/example.fdb
• jdbc
JDBC protocol
• firebirdsql
JDBC subprotocol, identifies driver to use
• //localhost:3050/c:/database/example.fdb
This is a database specific part, and identifies the database for the driver to connect, in the case
of Jaybird that is //<host>:<port>/<path to database>
The first part, jdbc:firebirdsql: is required by JDBC and specifies the so called protocol and
subprotocol for the JDBC connection. In other words, the type of connection that the application
wants to obtain, in this example it is a connection to a Firebird database.
9
Chapter 2. Obtaining a connection
package hello;
import java.sql.*;
Class.forName("org.firebirdsql.jdbc.FBDriver"); ①
// do something here
}
}
The first line of this code is important – it tells Java to load the Jaybird JDBC driver. As required by
the JDBC specification, at this point driver registers itself with java.sql.DriverManager.
We will leave out usages of Class.forName in further examples, they will work because of automatic
driver loading.
10
Chapter 2. Obtaining a connection
1. DriverManager loads the drivers from the system class path. This happens
automatically.
2. The application explicitly loads the driver’s class. This is only necessary if the
automatic loading (see previous item) is not available. This can be necessary
because the driver jar is loaded dynamically, through a different classloader,
etc).
The JDBC specification requires that during class initialization the driver
registers itself with DriverManager.
Class.forName("org.firebirdsql.jdbc.FBDriver");
3. The JDBC driver name is listed in the jdbc.drivers system property. Multiple
drivers can be separated using a colon (:).
You can specify the value of this property during JVM startup:
java\
-Djdbc.drivers=foo.Driver:org.firebirdsql.jdbc.FBDriver\
-classpath jaybird-full-{jaybird-example-
version}.jar;C:/myproject/classes\
my.company.SomeJavaExample
The second statement of the example tells the java.sql.DriverManager to open a database
connection to the Firebird server running on localhost, and the path to the database is
c:/database/employee.fdb.
The connection specification consists of the host name of the database server, optionally you can
specify a port (by default port 3050 is used). The host name can be specified using either its DNS
name (for example fb-server.mycompany.com or just fb-server), or its IP address (for example
192.168.0.5, or [1080::8:800:200C:417A] for an IPv6 address).
After the server name and port, the alias or path to the database is specified. We suggest to specify a
database alias instead of the absolute database path. For more information about using aliases, see
the documentation of Firebird server.
The format of the path depends on the platform of the Firebird server.
On Windows, the path must include the drive letter and path, for example
c:/database/employee.fdb, which points to the employee database that can be found in the database
directory of drive C:. Java (and Firebird) supports either / or \ (escaped as \\) as path separator on
the Windows platform. On Unix and Linux platform, you can use only / as the path separator.
On Unix platforms the path must include the root, as the path is otherwise interpreted relative to a
11
Chapter 2. Obtaining a connection
server-dependent folder. Having to include the root has the effect that a database in
/var/firebird/employee.fdb needs to use a double // after the host name (and port) in the
connection string: jdbc:firebirdsql://localhost//var/firebird/employee.fdb
It is possible to specify a relative path, but as this depends on the server configuration, this may be
confusing or easily lead to errors. We suggest not to use relative paths, and instead use an alias.
What if we want to specify additional connection parameters, for example a client encoding? The
JDBC API provides a method to specify additional connection properties:
package hello;
import java.sql.*;
import java.util.*;
props.setProperty("user", "SYSDBA");
props.setProperty("password", "masterkey");
props.setProperty("encoding", "UTF8");
// do something here
}
}
}
The user and password properties are defined in JDBC. All other property names, like encoding here,
are driver-specific.
Additional properties, for example the SQL role for the connection can be added to the props object.
The list of properties available in Jaybird can be found in Extended connection properties.
It is not always possible to use the above described method. Jaybird also provides a possibility to
specify extended properties in the JDBC URL.
12
Chapter 2. Obtaining a connection
jdbc:firebirdsql://host[:port]/<path to db>?<properties>
<properties> ::= <property>[{& | ;}<properties>]
<property> ::= <name>[=<value>]
The example below shows the specification for extended JDBC properties in the URL.
In this case extended properties are passed together with the URL using the HTTP-like parameter
passing scheme: first comes the main part of the URL, then "?", then name-value pairs separated
with & or ;. This example is equivalent to the previous example.
import java.sql.*;
...
Since: Jaybird 4
Jaybird 4 and higher support UTF-8 URL encoded values (and keys) in the query part of the JDBC
URL.
As a result of this change, the following previously unsupported characters can be used in a
connection property value when escaped:
• ; escaped as %3B
• + in the query part now means space (0x20), so occurrences of + (plus) need to be escaped as %2B;
make sure to do this for base64 encoded values of dbCryptConfig
• % in the query part now introduces an escape, so occurrences of % (percent) need to be escaped
as %25
URL encoding can also be used to encode any unicode character in the query string. Jaybird will
always use UTF-8 for decoding.
13
Chapter 2. Obtaining a connection
The support for URL encoding only applies to the JDBC URL part after the first ?. URL encoding
should not be applied for connection properties set through java.util.Properties or on a
javax.sql.DataSource.
The JDBC 2.0 specification introduced a mechanism to obtain database connections without
requiring the application to know any specifics of the underlying JDBC driver. The application is
only required to know the logical name to find an instance of the javax.sql.DataSource interface
using Java Naming and Directory Interface (JNDI). This is a common way to obtain connections in
web and application servers. Alternatively, the DataSource may be injected by CDI or Spring.
In order to obtain a connection via a DataSource object, you can use the code shown below. This
code assumes that you have correctly configured the JNDI properties. For more information about
configuring JNDI please refer to the documentation provided with your web or application server.
package hello;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
Usually, the binding between the DataSource object and its JNDI name happens in the configuration
of your web or application server. However under some circumstances (e.g. you are developing
your own JNDI-enabled application server/framework), you may have to do this yourself. You can
use this code snippet for this purpose:
14
Chapter 2. Obtaining a connection
import javax.naming.*;
import org.firebirdsql.ds.*;
...
FBSimpleDataSource ds = new FBSimpleDataSource();
ds.setDatabase("//localhost:3050/C:/database/employee.fdb");
ds.setUser("SYSDBA");
ds.setPassword("masterkey");
ctx.bind("jdbc/SomeDB", ds);
The DataSource implementation supports all connection properties available to the DriverManager
interface.
The next sections provide a description of these types and their configuration with the
corresponding JDBC URLs that should be used to obtain the connection of desired type. The type of
the JDBC driver for the javax.sql.DataSource is configured via a corresponding property.
The PURE_JAVA type (JDBC Type 4) uses a pure Java implementation of the Firebird wire protocol.
This type is recommended for connecting to a remote database server using TCP/IP sockets. No
installation is required except adding the JDBC driver to the class path. This type of driver provides
the best performance when connecting to a remote server.
In order to obtain a connection using the PURE_JAVA driver type you have to use a JDBC URL as
shown in Obtaining connection java.sql.DriverManager:
jdbc:firebirdsql://host[:port]/<path to database>
When using javax.sql.DataSource implementation, you can specify either "PURE_JAVA" or "TYPE4"
driver type, however this type is used by default.
The NATIVE and LOCAL types (JDBC Type 2) use a JNA proxy to access the Firebird client library and
requires installation of the Firebird client. The NATIVE driver type is used to access the remote
15
Chapter 2. Obtaining a connection
database server, the LOCAL type accesses the database server running on the same host by means of
IPC (Inter-Process Communication). Performance of NATIVE driver is approximately 10% lower
compared to the PURE_JAVA driver, but LOCAL type has up to 30% higher performance compared to
the PURE_JAVA driver when connecting the server on the same host. This is mostly due to the fact
that TCP/IP stack is not involved in this mode.
To create a connection using the NATIVE JDBC driver to connect to a remote server you have to use
the following JDBC URL with the native subprotocol:
jdbc:firebirdsql:native:host[/port]:<path to database>
When connecting to a local database server using the LOCAL driver, you should use following:
In addition to Jaybird, this requires a native Firebird client library, and JNA 5.5.0 needs to be on the
classpath.
When using Jaybird 3 and later, you can use a library to provide the Firebird client library for the
native and local protocol. For Windows and Linux, you can add the org.firebirdsql.jdbc:fbclient
dependency on your classpath. This dependency does not support the embedded protocol.
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>fbclient</artifactId>
<version>3.0.5.1</artifactId>
</dependency>
Windows
For Jaybird 3 and later, we recommend using the solution documented in Maven dependency for
native client.
On Windows, you need to make sure that fbclient.dll is located on the PATH environment variable.
Alternatively you can specify the directory containing this DLL in the jna.library.path system
property.
For example, if you put a copy of fbclient.dll in the current directory you have to use the
following command to start Java:
16
Chapter 2. Obtaining a connection
If your Java install is 32 bit, you need a 32 bit fbclient.dll, for 64 bit Java, a 64 bit fbclient.dll.
Linux
For Jaybird 3 and later, we recommend using the solution documented in Maven dependency for
native client.
On Linux, you need to make sure that libfbclient.so is available through the LD_PATH environment
variable.
Usually shared libraries are stored in the /usr/lib/ directory; however you will need root
permissions to install the library there. Some distributions will only have, for example,
libfbclient.so.2.5. In that case you may need to add a symlink from libfbclient.so to the client on
your system.
Alternatively you can specify the directory containing the library in the jna.library.path Java
system property. See the Windows example above for more details.
Limitations
Firebird client library is not thread-safe when connecting to a local database server using IPC.
Jaybird provides the necessary synchronization in Java code using a static object instance.
However, this static object instance is local to the classloader that has loaded the Jaybird classes.
In order to guarantee correct synchronization , the Jaybird driver must be loaded by the top-most
classloader. For example, when using the Type 2 JDBC driver with a web or application server, you
have to add the Jaybird classes to the main classpath (for example, to the lib/ directory of your web
or application server), but not to the web or Jave EE application, e.g. the WEB-INF/lib directory.
The Embedded server JDBC driver is a Type 2 JDBC driver that, rather than using the Firebird client
library, loads the Firebird embedded server library instead. This is the highest performance type of
JDBC driver for accessing local databases, as the Java code accesses the database file directly.
In order to obtain a connection via DriverManager you have to use following URL:
jdbc:firebirdsql:embedded:<path to database>
jdbc:firebirdsql:embedded:host[/port]:<path to database>
When host and, optionally, port is specified, embedded server acts as client library (i.e. you get the
same Type 2 behavior as you would get with using "native").
17
Chapter 2. Obtaining a connection
When using Firebird 3 embedded, you will need to make sure the necessary plugins like
engine12.dll/libengine12.so are accessible to the client library, consult the Firebird 3
documentation for more information. For an example, see the article Jaybird with Firebird
embedded example [https://www.lawinegevaar.nl/firebird/jaybird_embedded_example.html]
Limitations
The Firebird embedded server for Linux is not thread safe. Jaybird provides the needed
synchronization in Java code, similar to the one described for the Type 2 JDBC driver. This implies
the same restrictions on the classloader that will load the Jaybird classes.
The Firebird embedded server for Windows opens databases in exclusive mode. This means that
this particular database is accessible only to one Java virtual machine. There is no exclusive mode on
the POSIX platform. When the same database file is accessed by multiple JVM instances, database will
be corrupted!
The OOREMOTE type is a JDBC Type 4 specifically for use with OpenOffice.org and LibreOffice. It
addresses some differences in interpretation of the JDBC specification, and provides alternative
metadata in certain cases to allow OpenOffice.org and LibreOffice to function correctly.
jdbc:firebirdsql:oo://host[:port]/<path to database>
Since version 3.0, Jaybird no longer provides a connection pool. If you need a javax.sql.DataSource
implementation that provides a connection pool, either use the connection pool support of your
18
Chapter 2. Obtaining a connection
The most important method exposed by this interface is the getConnection() method, which will
return a connection based on the configuration of the data source. For a 'basic' (non-pooling) data
source this will create a new, physical, connection. For a connection pool, this will create a logical
connection that wraps a physical connection from the pool.
The 'user' of a connection should not care whether the connection is pooled or not,
the connection should behave the same from the perspective of the user, and the
user should use the connection in the same way. This should allow for swapping
between a non-pooling and pooling data source in an application without any
changes to the code using the data source.
When the application is done with the connection, it should call close() on the connection. A
connection from a non-pooling data source will be closed. For a logical connection from a
connection pool, close() will invalidate the logical connection (which will make it behave like a
closed connection), and return the underlying physical connection to the connection pool, where it
will be either kept for re-use, or maybe closed.
Use a connection for the shortest scope (and time) necessary for correct behaviour.
Get a connection, and close it as soon as you’re done. When using a connection
pool, this has the added benefit that just a few connections can serve the needs of
the application.
19
Chapter 2. Obtaining a connection
20
Chapter 3. Handling exceptions
All methods of the interfaces defined in the JDBC specification throw instances of
java.sql.SQLException to notify about error conditions that happen during request processing. The
SQLException is a checked exception, which forces Java programmers to either handle it with the
try/catch clause or redeclare it in the method signature.
There are good reasons to think about exception handling in your applications before you start
coding. First of all, it is very hard to change the exception handling pattern in existing code. The
changes will affect all layers above the place where the changes in exception handling are made
and the new application must be thoroughly tested after the change.
Another reason was already mentioned on the beginning of this chapter: instances of
java.sql.SQLException are the only way for the RDBMS server to notify about the error condition
that happened during request processing. By checking the error code which is sent with the
exception application can try to recover from the error.
And last but not least, there is resource management. When an exception happens in the method,
the execution flow of Java code differs from the normal flow, and only correctly coded application
will ensure that all allocated resources will be released. The resources in our case are JDBC
connections, statements, prepared statements and callable statements, result sets, etc. All these
objects not only take memory in the Java Virtual Machine of the application, but also consume
memory on the server, which, worst case, can lead to an unintended Denial-of-Service attack, as the
database server can no longer service requests.
A good exception handling strategy requires you do distinguish three kinds of error conditions:
• errors that the database access layer can detect and correctly handle; for example, the
application might decide to re-execute the business transaction if the database server returned
a deadlock error;
• errors that database access layer can detect, but is unable to handle; usually those are all
database errors that do not have special handling routines;
• errors that database access layer cannot detect without additional code unrelated to the
functionality of this layer; basically, all runtime exceptions fall into this category.
21
Chapter 3. Handling exceptions
• converting the generic SQLException into a generic business error in the application (this can be
throwing some generic exception defined in the application, but can also be an entry in the
application event log and short message that asks to retry the operation later);
• some emergency tactics, since the error that happened (e.g. NullPointerException or
OutOfMemoryError) was not considered while the application was created, thus possibly leaving it
in an unknown state; further operation should be considered dangerous and the corresponding
execution branch has to be halted.
The problem of resource management can be solved if resource allocation and deallocation
happens in the same code block and is protected with a try-with-resources block. The code to
recover from error conditions should use try/catch blocks. Example of such error and resource
handling code is presented below.
try {
updateSales.executeUpdate();
} catch(SQLException ex) {
if (ex.getErrorCode() == ...) {
// do something
} else {
throw new BusinessDBException(ex);
}
}
}
}
The nested try/catch block shows you an example of handling a deadlock error if it happens (first
scenario according to our classification), otherwise the exception is converted and passed to the
upper layers (second scenario). As you see, there is no special treatment to the third scenario.
A possible bug in the JDBC driver could have generated runtime exception in the
PreparedStatement.executeUpdate() method, which would lead to the statement handle leakage if
22
Chapter 3. Handling exceptions
the try-with-resource block had not been used to do the resource cleanup. As a rule of thumb,
always declare and allocate resources in a try-with-resources block: the resource will be
automatically closed/freed at the end of the block, even if exceptions occur.
Such coding practice might look weird, because on first sight the whole purpose of using the
PreparedStatement is neglected: the statement is prepared, used only once and then deallocated.
However, when this practice is combined with connection and statement pooling, it brings
enormous advantage to the application code. The code becomes much more manageable – resource
allocations and deallocations happen in the same method and the software developer does not
need to remember the places where the same prepared statement might be used – a statement pool
will either reuse the statement or it will prepare a new one, if it detects that all pooled prepared
statements are currently in use. As a side effect, the application will always use the minimum
number of statements handles, which in turn reduces the used resources on the database side.
3.2. Warnings
Some errors returned by Firebird are treated as warnings. They are converted into instances of
java.sql.SQLWarning class in the JDBC layer. These exceptions are not thrown from the driver
methods, but added to a connection instance.
Each next warning is appended to the tail of the warning chain. In order to read the warning chain,
use the code presented below.
import java.sql.*;
....
SQLWarning warning = connection.getWarnings();
while (warning != null) {
.... // do something with the warning
warning = warning.getNextWarning();
}
or
23
Chapter 3. Handling exceptions
import java.sql.*;
....
for (Throwable throwable : connection.getWarnings()) {
if (throwable instanceof SQLWarning) {
SQLWarning warning = (SQLWarning) throwable;
.... // do something with the warning
}
}
This second example will iterate over the first warning, all its causes (if any), and then on to other
warnings (if any), and so on.
An SQLException is a special exception that is thrown by the JDBC connectivity component in case of
an error. Each instance of this exception is required to carry the vendor error code (if applicable)
and a SQL state according to the X/Open SQLstate or SQL:2003 specifications. Firebird and Jaybird
[2]
use SQL:2003 SQL state codes.
When multiple SQL errors happened, they are joined into a chain. Usually the most recent
exception is thrown to the application, the exceptions that happened before can be obtained via
SQLException.getNextException() method. Alternatively, SQLException.iterator() can be used to
walk over all exceptions in the chain and their causes.
The JDBC specification provides an exception hierarchy that allows an application to react on the
error situations using regular exception handling rather than checking the error code. Error codes
may still be necessary for handling specific error cases.
[3]
The JDBC 4.3 specification defines the following exception hierarchy:
24
Chapter 3. Handling exceptions
Unfortunately Jaybird 3.0 does not yet fully use this exception hierarchy, we are
working to address this with the next versions of Jaybird.
Each of three layers in Jaybird use exceptions most appropriate to the specific layer. TODO List
needs revision
• Subclasses of java.sql.SQLException are thrown by the JDBC layer. Jaybird has a few subclasses
that might be interesting to the application:
25
Chapter 3. Handling exceptions
Applications can use the SQLstate codes in the error handling routines which should handle errors
that are returned from different databases. But since there is little agreement between RDBMS
vendors, this method can be used only for very coarse error distinction.
Here you can find a short list of error codes, symbolic names of a corresponding constant in a
org.firebirdsql.gds.ISCConstants class, the error message and short explanation of an error.
TODO Needs revising now Jaybird tries to pull the most important error code to the top
DDL errors happen during execution of DDL requests, and two primary error codes are used in
Firebird while executing the DDL operations. There are few other rare cases not mentioned here,
but the corresponding error messages contain enough information to understand the reason of an
error.
26
Chapter 3. Handling exceptions
Lock errors are reported by Firebird primarily when the application tries to modify a record which
is already modified by a concurrent transaction. Depending on the transaction parameters such
error can be reported either right after detection or after waiting some defined timeout hoping that
concurrent transaction will either commit or rollback and eventually release the resource. More
information on transaction locking modes can be found in section Using transactions.
27
Chapter 3. Handling exceptions
Referential integrity constraints ensure that the database remains in a consistent state after the
DML operation and/or whole transaction is completed. Three primary error codes are returned
when the defined constraints are violated. The error messages are self-explanatory.
This group contains secondary codes for the primary error code isc_dsql_error (335544569L), that
has a message "Dynamic SQL Error".
In most situations, Jaybird 3 and higher will put this secondary error code in the SQLException
instead of isc_dsql_error.
This table contains other errors that might be interesting to the application developer, however
they do not fall into any of the previous categories.
28
Chapter 3. Handling exceptions
29
Chapter 3. Handling exceptions
30
Chapter 4. Executing statements
• statements that change the state of the database but return no results;
• INSERT statements (or other statements with similar behaviour) that return the values of the
columns which were generated by the database engine while inserting the record.
Let’s check one of the typical usages shown below. In general the usage pattern of the statement
consists of three steps
① Create a Statement object by calling the createStatement() method of the Connection object.
② Use the Statement object by calling its methods, in our case we execute a simple query SELECT
firstName, lastName FROM users WHERE userId = 5. Processing of the query result will be
discussed in details in Working with result sets.
③ Close the result set and statement to release all allocated resources. In our example this is done
using the try-with-resources block. With try-with-resources. Java takes care of closing resources
in the right order, even if exceptions occur, or if a resource was not allocated (say, if
executeQuery throws an exception).
As the connection object is the factory for the statement objects, this puts a constraint on the object
lifetime: statements are bound to the connection; when the connection is closed, all statements that
31
Chapter 4. Executing statements
were created by that connection become invalid and the resources allocated by them are released.
However, despite that these resources are released when the connection closes, it is strongly
recommended to use the try-with-resources block, to guarantee that resources are released as soon
as possible because of reasons that will be discussed later.
These execute methods have several variants for additional features covered later (TODO check if
already covered).
It is allowed to use the same statement object to execute different types of queries one after other.
The code below contains a short example which first performs a select to find the ID of the user 'Joe
Doe', and if the record is found, it enables his account.
The concatenation of values into a query string as done in this example is not a
good practice as it can leave your code vulnerable to SQL injection.
In this specific case it is safe to do as the values are integers. In general: don’t do
this, use a prepared statement instead.
32
Chapter 4. Executing statements
Using the same statement object multiple times to enable user account
if (rowsUpdated == 0)
rowsUpdated = stmt.executeUpdate(
"INSERT INTO accounts (userId, enabled) " +
"VALUES (" + userId + ", 1)");
if (rowsUpdated != 1)
throw new SomeException(
"User was not updated correctly.");
}
}
The way the code is constructed is quite tricky because of the result set lifetime constraints that are
defined by the JDBC specification, please read the chapter Working with result sets for more details.
However, here it is done intentionally to emphasize that a single object is used to execute SELECT
and UPDATE/INSERT statements. It also shows how to check whether the executed statement modified
expected number of rows – the application first tries to update the account and only if no rows
were updated, it inserts new record into the accounts table.
This example of 'try update, then insert' approach can be better handled using
MERGE [https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/
fblangref25-dml-merge.html] or UPDATE OR INSERT [https://www.firebirdsql.org/file/
documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-update-or-insert.html].
33
Chapter 4. Executing statements
As mentioned earlier, the Statement.execute(String) method can also be used to execute statements
of an unknown type.
When a Java application executes a statement, a lot more operations happen behind the scenes:
1. A new statement object is allocated on the server. Firebird returns a 32-bit identifier of the
allocated object, a statement handle, that must be used in next operations.
2. An SQL statement is compiled into an executable form and is associated with the specified
statement handle.
3. Jaybird asks the server to describe the statement and Firebird returns information about the
statement type and possible statement input parameters (we will discuss this with prepared
statements) and output parameters, namely the result set columns.
4. If no parameters are required for the statement, Jaybird tells Firebird to execute statement
passing the statement handle into corresponding method.
After this Jaybird has to make a decision depending on the operation that was called.
• If Statement.execute() was used, Jaybird only checks the statement type to decide whether it
should return true, telling the application that there is a result set for this operation, or false, if
statement did not return any result set.
• If Statement.executeUpdate() was called, Jaybird asks Firebird to give the information about the
number of affected rows. This method can be called only if the statement type tells that no
result set can be returned by the statement.
34
Chapter 4. Executing statements
When called for queries, an exception is thrown despite the fact that the statement was
successfully executed on the server.
• If Statement.executeQuery() was called and the statement type indicates that a result set can be
returned, Jaybird constructs a ResultSet object and returns it to the application. No additional
checks, like whether the result set contains rows, are performed, as it is the responsibility of the
ResultSet object.
If this method is used for statements that do not return result set, an exception is thrown
despite the fact that the statement was successfully executed on the server.
The described behaviour may change in the future by throwing the exception
before executing the statement.
When an application does not need to know how many rows were modified, it should use the
execute() method instead of executeUpdate(). This saves an additional call to the server to get the
number of modified rows which can increase the performance in the situations where network
latency is comparable with the statement execution times.
The execute() method is also the only method that can be used when the application does not know
what kind of statement is being executed (for example, an application that allows the user to enter
SQL statements to execute).
After using the statement object, an application should close it. Two different possibilities exist: to
close the result set object associated with the statement handle and to close the statement
completely.
If, for example, we want to execute another query, it is not necessary to completely release the
allocated statement. Jaybird is required only to compile a new statement before using it, in other
words we can skip step 1 (allocating a new statement handle). This saves us one round-trip to the
server over the network, which might improve the application performance.
If we close the statement completely, the allocated statement handle is no longer usable. Jaybird
could allocate a new statement handle, however the JDBC specification does not allow use of a
Statement object after close() method has been called.
Step 2 (compiling the SQL statement) in the previous section is probably the most important, and
usually, most expensive part of the statement execution life cycle.
When Firebird server receives the "prepare statement" call, it parses the SQL statement and
converts it into the executable form: BLR. BLR, or Binary Language Representation, contains low-
level commands to traverse the database tables, conditions that are used to filter records, defines
the order in which records are accessed, indices that are used to improve the performance, etc.
When a statement is prepared, it holds the references to all database object definitions that are
used during that statement execution. This mechanism preserves the database schema consistency,
it saves the statement objects from "surprises" like accessing a database table that has been
35
Chapter 4. Executing statements
However, holding a reference on the database objects has one very unpleasant effect: it is not
possible to upgrade the database schema, if there are active connections to the database with open
statements referencing the objects being upgraded. In other words, if two application are running
and one is trying to modify the table, view, procedure or trigger definition while another one is
accessing those objects, the first application will receive an error 335544453 "object is in use".
To avoid this problem, it is strongly recommended to close the statement as soon as it is no longer
needed. This invalidates the BLR and release all references to the database objects, making them
available for the modification.
Special care should be taken when the statement pooling is used. In that case statements are not
released even if the close() method is called. The only possibility to close the pooled statements is
to close the pooled connections. Please check the documentation of your connection pool for more
information.
The PreparedStatement interface addresses such inefficiencies. An object that implements this
interface represents a precompiled statement that can be executed multiple times. If we use the
execution flow described in the "Statement dynamics" section, it allows us to go directly to the step
4 for repeated executions.
However, executing the same statement with the same values makes little sense, unless we want to
fill the table with the same data, which usually is not the case. Therefore, JDBC provides support for
parametrized statements – SQL statements where literals are replaced with question marks (?), so
called positional parameters. The application then assigns values to the parameters before
executing the statement.
Our first example in this chapter can be rewritten as shown below. At first glance the code becomes
more complicated without any visible advantage.
36
Chapter 4. Executing statements
if (rs.next()) {
int userId = rs.getInt(1);
if (rowsUpdated == 0) {
try (PreparedStatement stmt3 =
connection.prepareStatement(
"INSERT INTO accounts " +
"(userId, enabled) VALUES (?, 1)")) {
stmt3.setInt(1, userId);
rowsUpdated = stmt3.executeUpdate();
}
}
if (rowsUpdated != 1)
throw new SomeException(
"User was not updated correctly.");
}
}
}
}
• First, instead of using just one statement object we have to use three – one per statement.
• Second, before executing the statement we have to set parameters first. As is shown in the
example, parameters are referenced by their position. The PreparedStatement interface provides
setter methods for all primitive types in Java as well as for some widely used SQL data types
(BLOBs, CLOBs, etc.). The NULL value is set by calling the PreparedStatement.setNull(int) method.
• Third, we are now forced to use four nested try-with-resources blocks, which makes code less
readable.
So, where’s the advantage? First of all, prepared statements parameters protect against SQL
injection as the values are sent separately from the statement itself. It is not possible to change the
meaning of a statement due to incorrect string concatenation, so data leaks or other problems
cause by SQL injection can be avoided. Second of all, the driver handles conversion of Java object
37
Chapter 4. Executing statements
types to the correct format for the target datatype in Firebird: you don’t need to convert a Java
value to the correct string literal format for Firebirds SQL dialect.
To address some of the identified problems, we can redesign our application to prepare those
statements before calling that code (for example in a constructor) and close them when the
application ends. In that case the code can be more compact (see the next example). Unfortunately,
the application is now responsible for prepared statement management. When a connection is
closed, the prepared statement object will be invalidated, but the application will not be notified.
And when the application uses similar statements in different parts of the application, the
refactoring might affect many classes, possibly destabilizing the code. So, the refactoring on this
example is not something we want to do.
38
Chapter 4. Executing statements
......................
// query management
queryStmt.clearParameters();
queryStmt.setString(1, "Doe");
queryStmt.setString(2, "Joe");
try (ResultSet rs = queryStmt.executeQuery()) {
if (rs.next()) {
int userId = rs.getInt(1);
updateStmt.clearParameters();
updateStmt.setInt(1, userId);
int rowsUpdated = updateStmt.executeUpdate();
if (rowsUpdated == 0) {
insertStmt.clearParameters();
insertStmt.setInt(1, userId);
rowsUpdated = insertStmt.executeUpdate();
}
if (rowsUpdated != 1)
throw new SomeException(
"User was not updated correctly.");
}
}
......................
The answer to the advantage question is hidden in the prepareStatement(String) call. Since the
same statement can be used for different parameter values, the connection object could have a
possibility to perform prepared statement caching. A JDBC driver can ignore the request to close
the prepared statement, save it internally and reuse it each time application asks to prepare an SQL
statement that is known to the connection.
39
Chapter 4. Executing statements
Each stored procedure is allowed to take zero or more input parameters, similar to the
PreparedStatement interface. After being executed, a procedure can either return data in the output
parameters or it can return a result set that can be traversed. Though the interface is generic
enough to support database engines that can return both and have multiple result sets. These
features are of no interest to Jaybird users, since Firebird does not support them.
The IN and OUT parameters are specified in one statement. The syntax above does not allow to
specify the type of the parameter, therefore additional facilities are needed to tell the driver which
parameter is will contain output values, the rest are considered to be IN parameters.
Firebird stored procedures represent a piece of code written in the PSQL language that allows SQL
statement execution at the native speed of the engine and provides capabilities for a limited
execution flow control. The PSQL language is not general purpose language therefore its
capabilities are limited when it comes to interaction with other systems.
• Procedures that do not return any results. These are stored procedures that do not contain the
RETURNS keyword in their header.
• Procedures that return only a single row of results. These are stored procedures that contain the
RETURNS keyword in their header, but do not contain the SUSPEND keyword in their procedure
body. These procedures can be viewed as functions that return multiple values. These
procedures are executed by using the EXECUTE PROCEDURE statement.
• Procedures that return a result set, also called "selectable stored procedures". These are stored
procedures that contain the RETURNS keyword in their header and the SUSPEND keyword in their
procedure body, usually within a loop. Selectable procedures are executed using the "SELECT *
FROM myProcedure(…)" SQL statement. It is also allowed to use the EXECUTE PROCEDURE statement,
however that might produce strange results, since for selectable procedures is is equivalent to
executing a SELECT statement, but doing only one fetch after the select. If the procedure
implementation relies on the fact that all rows that it returns must be fetched, the logic will be
broken.
Consider the following stored procedure that returns factorial of the specified number.
40
Chapter 4. Executing statements
This procedure can be executed using the EXECUTE PROCEDURE call. When it is done in isql, the
output looks as follow
FACTORIAL
============
120
Now let’s modify this procedure to return each intermediate result to the client.
41
Chapter 4. Executing statements
If you create this procedure using the isql command line tool and then issue the "SELECT * FROM
factorial_selectable(5)" statement, the output will be like this:
ROW_NUM FACTORIAL
============ ============
0 1
1 1
2 2
3 6
4 24
5 120
Let’s see how the procedures defined above can be accessed from Java.
First, we can execute this procedure from the first example in the previous section using the
EXECUTE PROCEDURE statement and PreparedStatement, however this approach requires some
more code for result set handling.
42
Chapter 4. Executing statements
stmt.setInt(1, 2);
However, the standard for calling stored procedures in JDBC is to use the CallableStatement. The
call can be specified using the escaped syntax, but native Firebird EXECUTE PROCEDURE syntax is also
supported.
stmt.setInt(1, 2);
stmt.registerOutParameter(2, Types.INTEGER);
stmt.execute();
Please note the difference in the number of parameters used in the examples. The first example
contained only IN parameter on position 1 and the OUT parameter was returned in the ResultSet
on the first position, so it was accessed via index 1.
The latter example additionally contains the OUT parameter in the call. We have used the
CallableStatement.registerOutParameter method to tell the driver that the second parameter in our
call is an OUT parameter of type INTEGER. Parameters that were not marked as OUT are considered
by Jaybird as IN parameters. Finally the "EXECUTE PROCEDURE factorial(?)" SQL statement is
prepared and executed. After executing the procedure call we get the result from the appropriate
getter method.
It is worth mentioning that the stored procedure call preparation happens in the
CallableStatement.execute method, and not in the prepareCall method of the Connection object.
Reason for this deviation from the specification is that Firebird does not allow to prepare a
procedure without specifying parameters and set them only after the statement is prepared. It
seems that this part of the JDBC specification is modelled after the Oracle RDBMS and a
workaround for this issue had to be delivered. Another side effect of this issue is, that it is allowed
to intermix input and output parameters, for example in the "IN, OUT, IN, OUT, OUT, IN" order. Not
43
Chapter 4. Executing statements
that it makes much sense to do this, but it might help in some cases when porting applications from
another database server.
It is also allowed to use a procedure call parameter both as an input and output parameter. It is
recommended to use this only when porting applications from the database servers that allow
INOUT parameter types, such as Oracle.
The actual stored procedure call using the CallableStatement is equivalent to the call using the
prepared statement as shown in the first example. There is no measurable performance differences
when using the callable statement interface.
The JDBC specification allows another syntax for the stored procedure calls:
stmt.registerOutParameter(1, Types.INTEGER);
stmt.setInt(2, 2);
stmt.execute();
Note, that input parameter now has index 2, and not 1 as in the previous example. This syntax
seems to be more intuitive, as it looks like a function call. It is possible to use this syntax for stored
procedures that return more than one parameter by combining code from the second and the last
examples.
Firebird stored procedures can also return result sets. This is achieved by using the SUSPEND
keyword inside the procedure body. This keyword returns the current values of the output
parameters as a single row to the client.
The following example is more complex and shows a stored procedure that computes a set of
factorial of the numbers up to the specified number of rows.
The SELECT SQL statement is the natural way of accessing the selectable procedures in Firebird.
You "select" from such procedures using the Statement or PreparedStatement objects.
With minor issues it is also possible to access selectable stored procedures through the
CallableStatement interface. The escaped call must include all IN and OUT parameters. After the call
is prepared, parameters are set the same way. However, the application must explicitly tell the
driver that selectable procedure is used and access to the result set is desired. This is done by
calling a Jaybird-specific method as shown in the example below. When this is not done, the
application has access only to the first row of the result set. TODO Outdated?
The getter methods from the CallableStatement interface will provide you access only to the first
row of the result set. In order to get access to the complete result set you have to either call the
44
Chapter 4. Executing statements
import java.sql.*;
import org.firebirdsql.jdbc.*;
...
try (CallableStatement stmt = connection.prepareCall(
"{call factorial(?, ?, ?)}")) {
FirebirdCallableStatement fbStmt =
(FirebirdCallableStatement)stmt;
fbStmt.setSelectableProcedure(true);
stmt.setInt(1, 5);
stmt.registerOutParameter(2, Types.INTEGER); // first OUT
stmt.registerOutParameter(3, Types.INTEGER); // second OUT
while(rs.next()) {
int firstCol = rs.getInt(1); // first OUT
int secondCol = rs.getInt(2); // second OUT
int anotherSecondCol = stmt.getInt(3); // second OUT
}
}
}
Note that OUT parameter positions differ when they are accessed through the ResultSet interface
(the firstCol and secondCol variables in our example). They are numbered in the order of their
appearance in the procedure call starting with 1.
When OUT parameter is accessed through the CallableStatement interface (the anotherSecondCol
parameter in our example), the registered position should be used. In this case the result set can be
used for navigation only.
The PreparedStatement.getMetaData method is used to obtain description of the columns that will be
returned by the prepared SELECT statement. The method returns an instance of
java.sql.ResultSetMetaData interface that among other descriptions provides the following:
• column type, name of the type, its scale and precision if relevant;
• information whether the column is read-only or writable, whether it contains signed numbers,
whether it can contains NULL values, etc.
Additionally, the JDBC 3.0 specification introduced the interface java.sql.ParameterMetaData that
45
Chapter 4. Executing statements
provides similar information for the input parameters of both PreparedStatement and
CallableStatement objects.
Due to the implementation specifics of the escaped syntax support for callable
statements, it is not allowed to call getParameterMetaData before all OUT parameters
are registered. Otherwise the driver will try to prepare a procedure with an
incorrect number of parameters and the database server will generate an error.
The Statement interface defines three methods for batch updates: addBatch, executeBatch and
clearBatch. It is allowed to add arbitrary INSERT/UPDATE/DELETE or DDL statement to the batch
group. Adding a statement that returns result set is an error.
The JDBC specification recommends to turn the auto-commit mode off to guarantee standard
behavior for all databases. The specification explicitly states that behavior in auto-commit case is
implementation defined.
In auto-commit mode, Jaybird executes a batch in a single transaction, i.e. the "all-or-nothing"
principle. A new transaction is started before the batch execution and is committed if there were no
exceptions during batch execution, or is rolled back if at least one batch command generated an
error.
The Statement.executeBatch method submits the job to the database server. In case of successful
execution of the complete batch, it returns an array of integers containing update counts for each of
the commands. Possible values are:
• Statement.SUCCESS_NO_INFO – driver does not have any information about the update count, but it
knows that statement was executed successfully.
46
Chapter 4. Executing statements
The Statement.executeBatch method closes the current result set if one is open. After successful
execution the batch is cleared. Calling execute, executeUpdate and executeQuery before the batch is
executed does not have any effect on the currently added batch statements.
If at least one statement from the batch fails, a java.sql.BatchUpdateException is thrown. Jaybird
will stop executing statements from batch after the first error. In auto-commit mode it will also
rollback the transaction. An application can obtain update counts for the already executed
statements using getUpdateCounts method of the BatchUpdateException class. The returned array will
always contain fewer entries than there were statements in the batch, as it will only report the
update counts of succesfully executed statements.
Using batch updates with a prepared statement is conceptually similar to the java.sql.Statement
approach. The main difference is that only one statement can be used, but with different sets of
parameter values.
stmt.setInt(1, 1);
stmt.setString(2, "apple");
stmt.addBatch();
stmt.setInt(1, 2);
stmt.setString(2, "orange");
stmt.addBatch();
stmt.setInt(1, 1);
stmt.setString(2, "apple");
stmt.addBatch();
stmt.setInt(1, 2);
stmt.setString(2, "orange");
stmt.addBatch();
47
Chapter 4. Executing statements
• scalar functions
• outer joins
For example {fn concat('Firebird', 'Java')} concatenates these two words into 'FirebirdJava'
literal. "Supported JDBC Scalar Functions" provides a list of supported scalar functions.
It is possible to include date and time literals in SQL statements. In order to guarantee that each
database will interpret the literal identically, the JDBC specification provides following syntax to
specify them:
{d 'yyyy-mm-dd'}
{t 'hh:mm:ss'}
48
Chapter 4. Executing statements
Due to the various approaches to specify outer joins (for instance, the Oracle "(+)" syntax), the JDBC
specification provides the following syntax:
The escaped syntax for stored procedures is described in details in the the section The
java.sql.CallableStatement interface.
The percent sign (%) and underscore (_) characters are wild cards in LIKE clause of the SQL
statement. In order to interpret them literally they must be preceded by the backslash character (\)
that is called the escape character. The escaped syntax for this case identifies which character is
used as an escape character:
[4] DDL – Data Definition Language. This term is used to group all statements that are used to manipulate database schema, i.e.
creation of tables, indices, views, etc.
[5] escape syntax in limited form also works for Statement and PreparedStatement
[6] Support is expected in Firebird 4 for prepared statements, Jaybird will add support in a future version
49
Chapter 4. Executing statements
50
Chapter 5. Working with result sets
• TYPE_FORWARD_ONLY – the result set is not scrollable, cursor can only move forward. When the
TRANSACTION_READ_COMMITTED isolation level is used, the result set will return all rows that are
satisfying the search condition at the moment of fetch (which will be every fetch size calls to
ResultSet.next()). In other cases result set will return only rows that were visible at the
moment of the transaction start.
• TYPE_SCROLL_INSENSITIVE – the result set is scrollable, the cursor can move back and forth, can be
positioned on the specified row. Only rows satisfying the condition at the time of query
execution are visible.
Result set concurrency specifies whether the result set object can be updated directly or a separate
SQL request should be used to update the row. Result sets that allow direct modification using the
ResultSet.updateXXX methods are usually used in GUI applications which allow in-place editing of
the underlying result set.
The result set concurrency is specified during statement creation and cannot be changed later.
Jaybird supports two types of result set concurrency:
• CONCUR_READ_ONLY is available for all types of result sets. It tells the driver that direct update of
the result set is not possible and all ResultSet.updateXXX methods should throw an exception.
• CONCUR_UPDATABLE is supported only under certain conditions that are needed for the driver to
correctly construct a DML request that will modify exactly one row. These conditions are:
◦ the SELECT statement that generated the result set references only one table;
51
Chapter 5. Working with result sets
◦ all columns that are not referenced by the SELECT statement allow NULL values, otherwise it
won’t be possible to insert new rows;
◦ the SELECT statement does not contain the DISTINCT predicate, aggregate functions, joined
tables, or stored procedures;
◦ the SELECT statement references all columns of the tables primary key definition or the
RDB$DB_KEY column.
Result set holdability informs the driver whether result sets should be kept open across commits.
ResultSet.HOLD_CURSORS_OVER_COMMIT tells the driver to keep the result set object open, while
ResultSet.CLOSE_CURSORS_AT_COMMIT tells driver to close them on commit.
When an application calls Connection.commit(), the Firebird server closes all open result sets. It is
not possible to tell the server to keep a result set open over commit unless "commit retaining" mode
is used. This mode is global for the complete connection and is not suitable for holdability control
on a statement level. Use of "commit retaining" mode is believed to have an undesired side-effect
for read-write transactions as it inhibits garbage collection. Because of these reasons "commit
retaining" is not used in Jaybird during normal execution. Applications are able to commit the
transaction keeping the result sets open by executing a "COMMIT RETAIN" SQL statement.
To support holdable result sets, Jaybird will upgrade the result set to TYPE_SCROLL_INSENSITIVE to
cache all rows locally, even if you asked for a TYPE_FORWARD_ONLY result set. See also ResultSet Types.
The current implementation does not allow to call getResultSet() method after
using the executeQuery(String) method of the Statement class. The JDBC
specification is unclear on this topic and JDBC drivers of different vendors treat it
differently.
52
Chapter 5. Working with result sets
Depending on the type of the result set, it is possible to move the cursor either forward only (next
example [#using-forward-only]) or using absolute and relative positioning (second example below [#
using-scrollable-updatable]).
Values of the result set are obtained by calling the corresponding getter method depending on the
type of column. For example the ResultSet.getInt(1) method returns the value of the first column
as an int value. If value of the column is not integer, Jaybird tries to convert it according to the
"Data Type Conversion Table" specified in Data Type Conversion Table. If conversion is not possible,
an exception is thrown.
There are two possibilities to obtain data from the result set columns: by column label or by column
position. Position of the first column is 1. Names supplied to getter methods are case-insensitive.
The search first happens in the column aliases, and if no match found, driver checks the original
column names. If there is more then one column matching the specified name (even if the original
names were quoted), the first match is taken. TODO: Behavior changed with Jaybird 2.2, verify
and update
When getters for primitive types are used and original value in the result set is NULL, driver returns
a default value for that type. For example getInt() method will return 0. In order to know whether
the value is really 0 or NULL, you have to call ResultSet.wasNull() method after calling the get
method.
Getters that return object values (getString, getDate, getObject, etc.) will return a null value for
columns containing NULL. Calling wasNull after object get methods is possible but unnecessary.
53
Chapter 5. Working with result sets
while(rs.next()) {
int id = rs.getInt(1);
String name = rs.getString("name");
double price = rs.getDouble(3);
}
}
Scrollable cursors are especially useful when result of some query is displayed by the application
which also allows the user to directly edit the data and post the changes to the database.
ResultSet rs = scrollStatement.executeQuery(
"SELECT id, name, price FROM myTable");
rs.moveToInsertRow();
rs.updateInt(1, newId);
rs.updateString(2, newName);
rs.updateDouble(3, newPrice);
rs.insertRow();
rs.moveToCurrentRow();
rs.relative(-2);
The code example above shows how to update first row, insert new one and after that move two
records backwards.
An application can also update the current row using so called "positioned updates" on named
cursors. This technique can be used only with forward-only cursors, since application can update
only the row to which the server-side cursor points to. In case of scrollable cursors the complete
result set is fetched to the client and then the server-side cursor is closed. The example below [#
using-positioned-updates] shows how to use positioned updates.
54
Chapter 5. Working with result sets
First, the application has to specify the name of the cursor and the list of the columns that will be
updated before the query is executed. This name is later used in the UPDATE statement as shown in
the example.
connections.setAutoCommit(false);
try (Statement selectStmt = connection.createStatement();
Statement updateStmt = connection.createStatement()) {
selectStmt.setCursorName("someCursor");
while(rs.next()) {
...
if (someCondition) {
updateStmt.executeUpdate("UPDATE myTable " +
"SET myColumn = myColumn + 1 " +
"WHERE CURRENT OF " + rs.getCursorName());
}
}
}
}
A result set is closed by calling the ResultSet.close() method. This releases the associated server
resources and makes the ResultSet object available for garbage collection. It is strongly
recommended to explicitly close result sets in auto-commit mode or
ResultSet.TYPE_SCROLL_INSENSITIVE result sets, because this releases memory used for the cached
data. Whenever possible, use try-with-resources.
The result set object is also closed automatically, when the statement that created it is closed or re-
executed. In auto-commit mode, the result set is closed automatically if any statement is executed
on the same connection.
55
Chapter 5. Working with result sets
56
Chapter 6. Using transactions
This model however cannot be applied to each database engine in the world and the designers of
the JDBC API have chosen a model where each database connection has one and only one active
transaction associated with it. Also, unlike the Firebird model, where transactions require explicit
start, JDBC specification requires the driver to start transaction automatically as soon as a
transactional context is needed.
The following code shows a very simple example of using transactions in JDBC where a
hypothetical intruder that increases salary of each employee twice and uses explicit transaction
control in JDBC. It also tries to hide his own identity and if the operations succeed, he commits the
transaction, otherwise he rolls the changes back.
connection.setAutoCommit(false); ①
connection.commit(); ③
} catch(SQLException ex) {
connection.rollback(); ④
}
In order to use transactions, the application first switches the auto-commit mode off (see below for
57
Chapter 6. Using transactions
more information), then creates a java.sql.Statement object, executes an UPDATE statement. Please
note, that there is no explicit transaction start, a new transaction will be started right before
executing the statement (step 2).
If we work with a database where not only referential integrity is preserved, but also reasonable
security rules are encoded in the triggers, it will raise an error preventing cleaning the audit trails
information. In this case the intruder chooses to undo all the changes he made, so that nobody
notices anything. But if no security rules are implemented, he commits the transaction.
Firebird PSQL has an IN AUTONOMOUS TRANSACTION block that can be used to prevent
such abuse and prevent audit-records from being wiped out by a transaction
rollback.
When a connection uses explicit transaction control, each transaction must be finished by calling
the commit() or rollback() methods of the Connection object before the connection is closed. If a
transaction was not finished, but the close method is called, the active transaction is rolled back
automatically. This also happens when the transaction was not finished, the connection was not
closed explicitly and that Connection object became eligible for garbage collection. In this case, the
close() method is implicitly invoked by the class finalizer, which in turn rolls the transaction back.
• For select statements, statement is complete when the associated result set is closed. The result
set is closed as soon as one of the following occurs:
• For CallableStatement objects, the statement is complete, when all of the associated result sets
have been closed.
If there is an ongoing transaction and the value of the auto-commit property is changed, the current
transaction is committed.
Note, when a connection is obtained via javax.sql.DataSource object and container managed
58
Chapter 6. Using transactions
transactions are used (for example, the application is executing inside an EJB container), it is an
error to call setAutoCommit method.
Special care should be taken when using multiple statements in auto-commit mode. The JDBC 2.0
specification did not fully define the rules for the statement completion as it did not define the
behavior of multiple ResultSet objects created using the same connection object in auto-commit
mode.
Since Firebird does not allow the result set to remain open after the transaction ends, Jaybird 1.5.x
and below cached the complete result set in memory when the SELECT statements were executed
and corresponding transaction was committed. This had an adverse effect on allocated memory
when the result set is big, especially when it contains BLOB fields. The JDBC 3.0 specification
addressed this unclear situation (see above) and Jaybird 2.1 was improved to correctly handle
them. It also allowed to improve the memory footprint – the driver no longer caches non-scrollable
and non-holdable result sets in memory.
However, some Java applications that do not conform the current JDBC specification might no
longer work with Jaybird 2.1 and above unless additional steps are taken.
The piece of code below works perfectly with explicit transaction control. However, it won’t work
correctly with auto-commit with a driver - like Jaybird - that complies with the JDBC 3.0
specification, when the selectStmt and updateStmt object are created by the same connection object
(step 1). When the UPDATE is executed in step 3, the result set produced by the SELECT statement
must be closed before the execution. When the Java application tries to fetch the next record by
calling the rs.next() method, it will receive an SQLException with a message "The result set is
closed".
The only correct solution to this situation is to fix the application by either using explicit
transaction control, or by using two connection objects, one for SELECT statement and one for
UPDATE statement.
ResultSet rs = selectStmt.executeQuery(
"SELECT * FROM myTable");
while(rs.next()) { ②
int id = rs.getInt(1);
String name = rs.getString(2);
Unfortunately, not all applications can be changed either because there is no source code available
or, simply, because any change in the code requires complete release testing of the software. To
address this, Jaybird 2.1 introduced the connection parameter defaultHoldable which makes result
59
Chapter 6. Using transactions
sets holdable by default. The holdable result sets will be fully cached in memory, but won’t be
[8]
closed automatically when transaction ends. This property also affects the default holdability of
result sets when auto-commit is disabled.
Another reason is that long running read-write transactions inhibit the process of collecting
garbage, i.e. a process of identifying previous versions of the database records that are no longer
needed and releasing the occupied space for the new versions. Without garbage collection the
database size will grow very fast and the speed of the database operations will decrease, because
the database engine will have to check all available record versions to determine the appropriate
one.
Therefore, if you are sure that application won’t modify the database in the transaction, use the
setReadOnly method of the java.sql.Connection object to tell the server that the transaction is read-
only.
60
Chapter 6. Using transactions
Firebird, however, defines other isolation levels: read_committed, concurrency and consistency. Only
the read_committed isolation level can be mapped to the same level defined by the ANSI/ISO SQL
standard. Dirty reads are prevented, non-repeatable reads as well as phantom reads can occur.
The concurrency isolation level is stronger than repeatable read isolation defined in ANSI/SQL
standard and satisfies the requirements of a serializable isolation level, however, unlike RDBMSes
with locking concurrency control, it guarantees better performance.
And finally Firebird provides a consistency isolation level which in combination with table
reservation feature guarantees the deadlock-free execution of transactions. A transaction will be
prevented from starting if there is already another one with the overlapping sets of the reserved
tables. This isolation level guarantees truly serial history of transaction execution.
In order to satisfy the JDBC specification Jaybird provides a following default mapping of the JDBC
transaction isolation levels into Firebird isolation levels:
The default mapping is specified in the isc_tpb_mapping.properties file that can be found in the
Jaybird archive and can be overridden via the connection properties
• via the tpbMapping property that specifies the path to the PropertiesResourceBundle with the new
mapping of the isolation level;
• via the direct specification of the JDBC transaction isolation level. The following code contains
an example of such operation, the values in the mapping are described in section "Transaction
Parameter Buffer".
61
Chapter 6. Using transactions
The overridden mapping is used for all transactions started within the database connection. If the
default mapping is overridden via the data source configuration, it will be used for all connections
created by the data source.
6.5. Savepoints
Savepoints provide finer-grained control over transactions by providing intermediate steps within
a larger transaction. Once a savepoint has been set, transaction can be rollback to that point
without affecting preceding work.
stmt.executeUpdate(
"INSERT INTO myTable(id, name) VALUES (1, 'John')");
Savepoint savePoint1 =
connection.setSavepoint("savepoint_1");
stmt.executeUpdate(
"UPDATE myTable SET name = 'Ann' WHERE id = 1");
...
connection.rollback(savePoint1);
Note, rolling back to the savepoint automatically releases and invalidates any savepoints that were
62
Chapter 6. Using transactions
If the savepoint is no longer needed, you can use the Connection.releaseSavepoint method to release
system resources. After releasing a savepoint it is no longer possible to rollback the current
transaction to that savepoint. Attempts to call the rollback(Savepoint) method will result in an
SQLException. Savepoints that have been created within a transaction are automatically released
when that transaction is committed or rolled back.
• and, finally, the table reservations – their names and reservation modes.
The TPB is automatically generated depending on the transaction isolation level specified for the
java.sql.Connection object. Usually there is no need to manipulate the TPB directly. Additionally, if
the connection is set to read-only mode, this is reflected in the TPB by appropriate constant.
However, the lock resolution mode as well as table reservations cannot be specified by using the
standard JDBC interfaces. For the cases where this is needed, Jaybird provides an extension of the
JDBC standard.
FirebirdConnection fbConnection =
(FirebirdConnection)connection;
TransactionParameterBuffer tpb =
fbConnection.createTransactionParameterBuffer();
tpb.addArgument(TransactionParameterBuffer.READ_COMMITTED);
tpb.addArgument(TransactionParameterBuffer.REC_VERSION);
tpb.addArgument(TransactionParameterBuffer.WRITE);
tpb.addArgument(TransactionParameterBuffer.WAIT);
tpb.addArgument(TransactionParameterBuffer.LOCK_TIMEOUT, 15);
fbConnection.setTransactionParameters(tpb);
The above presents an example of populating the TPB with custom parameters.
Firebird supports three isolation levels: read_committed, concurrency and consistency which are
63
Chapter 6. Using transactions
In consistency and concurrency modes Firebird database engine loads the different versions of the
same record from disk and checks the "timestamps" of each version and compares it with the
"timestamp" of the current transaction. The record version with the highest timestamp that is
however lower or equal to the timestamp of the current transaction is returned to the application.
This effectively returns the version of the record that was when the current transaction started and
guarantees that neither non-repeatable reads nor phantom reads can ever occur.
In read_committed mode, the Firebird database engine accesses the record version with the highest
timestamp for which the corresponding transaction is marked as committed. This prevents engine
from reading the record versions which were modified in concurrent transactions that are not yet
committed or were rolled back for whatever reasons. However, such mode allows non-repeatable
reads as well as phantom reads if the concurrent transaction that modified records or inserted new
ones had been committed.
The read_committed isolation mode requires another constant that specifies the behavior of the
transaction when it sees a record version with a timestamp that belongs to a currently running
transaction which is not yet committed.
• TranscationParameterBuffer.READ and
• TransactionParameterBuffer.WRITE
When the read-write mode (constant WRITE) is specified, the database engine stores the "timestamp"
of the new transaction in the database even when no modification will be made in the transaction.
The "timestamp" affects the garbage collection process, since the database engine cannot release
records that were modified in transactions with higher "timestamps" even when these record
versions are no longer needed (in other words, when there are already newer versions of the
records). Thus, long-running read-write transaction inhibits the garbage collection even when no
modifications are done in it.
Therefore, it is recommended to set the read-only mode for the transaction when it is used for read
operations.
64
Chapter 6. Using transactions
Relational database systems that use pessimistic locking for concurrency control lock the records
regardless of the operation type, read or write. When an application tries to read a record from the
database, the database engine tries to obtain a "read lock" to that record. If the operation succeeds
and the application later tries to update the record, the lock is upgraded to a "write lock". And
finally, if the resource is already locked for write, concurrent transactions cannot lock it for
reading, since the system cannot allow the transaction to make a decision based on data that might
be rolled back later. This approach significantly decreases concurrency. However, databases
systems that employ a record versioning mechanism do not have such restrictions because each
transaction "sees" its own version of the record – the only possible conflict happens when two
concurrent transactions try to obtain "write lock" for the same database record.
Firebird belongs to the latter, and on read_committed and concurrency isolation levels it behaves
appropriately – there are no lock conflicts between readers and writers, and only writers
competing for the same resource raise a lock conflict. However, on the consistency isolation level
Firebird emulates the behavior of systems with pessimistic locking – read operations will conflict
with write operations. Even more, the locks are obtained for whole tables (see "Table Reservation"
for details).
The following table summarizes the above for Firebird 2.0. It shows that read-committed or
repeatable read transactions conflict only when they simultaneously update the same rows. In
contrast, a consistency transaction conflicts with any transaction running in read-write mode, e.g.
as soon as a consistency transaction gets write access to a table, other read-write transactions are
not allowed to make changes in that tables.
Table 2. Lock conflicts within one table depending on the isolation level
Read-committed, Concurrency
read-only
The table reservation is specified via a TPB and includes the table to lock, the lock mode (read or
write) and lock type (shared, protected and exclusive).
65
Chapter 6. Using transactions
tpb.addArgument(TransactionParameterBuffer.CONSISTENCY); ②
tpb.addArgument(TransactionParameterBuffer.WRITE);
tpb.addArgument(TransactionParameterBuffer.NOWAIT);
tpb.addArgument(TransactionParameterBuffer.LOCK_WRITE,
"TEST_LOCK");
tpb.addArgument(TransactionParameterBuffer.PROTECTED);
connection.setTransactionParameters(tpb); ③
This shows an example of reserving the TEST_LOCK table for writing in a protected mode. The code
does the following:
② Populate the TPB. The first three statements were described in "Transaction Parameter Buffer".
The fourth call specifies that the application wants to obtain a lock on the table TEST_LOCK for
writing. The fifth call specifies the type of the lock to obtain, in our case the protected lock.
The lock mode to the table specified in the TPB can be either
The lock conflict table depends on the isolation level of the transactions and has the following
properties:
• LOCK_WRITE mode always conflicts with another LOCK_WRITE mode regardless of the lock type and
transaction isolation mode;
• LOCK_WRITE always conflicts with another LOCK_READ mode if both transactions have consistency
isolation, but has no conflict with shared-read locks if the other transaction has either
66
Chapter 6. Using transactions
[7] Additionally, before the InterBase was open-sourced, this allowed application developers to create multi-threaded application
without need to purchase additional user licenses.
[8] Other cases, e.g. closing the statement object or the connection object will still ensure that the result set object is closed. If you
need result sets that can be "detached" from the statement object that created them, please check the javax.sql.RowSet
implementations.
[9] This approach follows the two-phase locking protocol, where all locks are acquired on the beginning of the transaction and are
released only when transaction is finished.
67
Chapter 6. Using transactions
68
Chapter 7. Working with Services
The actual execution of the Services API calls can be viewed as a tasks triggered from the client
application to be executed on server. The parameters passed in the calls are internally used to
construct the string similar to the one that is passed to command-line tools. Later this string is
passed into entry routine of the gbak, gfix, gsec or gstat utility. The output of the utility, which in
normal case is printed to standard out, is in this case transmitted over the network to the client
application.
Jaybird attempts to hide the complexity of the original API by providing a set of interfaces and their
implementations to perform the administrative tasks regardless of the usage mode (i.e. remote
server and embedded engine, wire protocol and access via native client library).
This chapter describes the available Java API for the administrative tasks. All classes and interfaces
described below are defined in the org.firebirdsql.management package. Each management class
works as a standalone object and does not require an open connection to the server.
7.1. ServiceManager
The ServiceManager interface and the FBServiceManager class are defined as the common
superclasses providing setters and getters for common properties as well as some common
routines. The following properties can be specified:
The last parameter requires some explanation. The calls to all Services API routines are
asynchronous. The client application can start the call, but there are no other means to find out
whether execution of the service call is finished or not except reading the output of the service call
69
Chapter 7. Working with Services
The FBServiceManager converts the asynchronous calls into synchronous by constantly polling the
service output stream. If the logger property is specified the received data is copied into the
specified OutputStream, otherwise it is simply ignored and the EOF-marker is being watched.
This behavior can be changed by overriding the appropriate method in the FBServiceManager class
and/or subclasses. The only requirement is to detach from the service manager when it is no longer
needed.
70
Chapter 7. Working with Services
In addition to the properties, the following methods are used to configure the paths to backup and
database files when multi-file backup or restore operations are used.
Method Description
addBackupPath(String) Add a path to a backup file from a multi-file backup.
Should be used for restore operation only.
addBackupPath(String, int) Add a path to the multi-file backup. The second
parameter specifies the maximum size of the particular
file in bytes. Should be used for backup operation only.
addRestorePath(String, int) Add a path for the multi-file database. The second
parameter specifies the maximum size of the database
file in pages (in other words, the maximum size in bytes
can be obtained by multiplying this value by
restorePageSize parameter)
clearBackupPaths() Clear all the specified backup paths. This method also
clears the path specified in backupPath property.
clearRestorePaths() Clear all the specified restore paths. This method also
clears the path specified in the database property.
71
Chapter 7. Working with Services
All paths specified are paths specifications on the remote server. This has the
following implications:
b. it is not possible to restore from the local or network drive unless it is mounted
on the remote server.
After specifying all the needed properties, the application developer can use backupDatabase(),
backupMetadata() and restoreDatabase() methods to perform the backup and restore tasks. These
methods will block until the operation is finished. If the logger property was set, the output of the
[10]
service will be written into the specified output stream, otherwise it will be ignored.
backupManager.setHost("localhost");
backupManager.setPort(3050);
backupManager.setUser("SYSDBA");
backupManager.setPassword("masterkey");
backupManager.setLogger(System.out);
backupManager.setVerbose(true);
backupManager.setDatabase("C:/database/employee.fdb");
backupManager.setBackupPath("C:/database/employee.fbk");
backupManager.backupDatabase();
...
// and restore it back
BackupManager restoreManager = new FBBackupManager();
restoreManager.setHost("localhost");
restoreManager.setPort(3050);
restoreManager.setUser("SYSDBA");
restoreManager.setPassword("masterkey");
restoreManager.setLogger(System.out);
restoreManager.setVerbose(true);
restoreManager.setRestoreReplace(true); // attention!!!
restoreManager.setDatabase("C:/database/employee.fdb");
restoreManager.setBackupPath("C:/database/employee.fbk");
backupManager.restoreDatabase();
72
Chapter 7. Working with Services
Constant Description
73
Chapter 7. Working with Services
Constant Description
74
Chapter 7. Working with Services
Constant Description
75
Chapter 7. Working with Services
restoreManager.setHost("localhost");
restoreManager.setPort(3050);
restoreManager.setUser("SYSDBA");
restoreManager.setPassword("masterkey");
restoreManager.setLogger(System.out);
restoreManager.setVerbose(true);
restoreManager.setRestoreReplace(true); // attention!!!
restoreManager.setDatabase("C:/database/employee.fdb");
restoreManager.setBackupPath("C:/database/employee.fbk");
The next service available is the user management. The routines are defined in the UserManager
interface and are implemented in the FBUserManager class. Additionally, there is an User interface
providing getters and setters for properties of a user account on the server and corresponding
[13]
implementation in the FBUser class. The available properties of the FBUser class are:
76
Chapter 7. Working with Services
The management class, FBUserManager has following methods to manipulate the user accounts on
the server:
Method Description
getUsers():Map Method delivers a map containing user names as keys
and instances of FBUser class as values containing all
users that are registered on the server. The instances of
FBUser class do not contain passwords, the
corresponding property is null.
addUser(User) Register the user account on the server.
updateUser(User) Update the user account on the server.
deleteUser(User) Delete the user account on the server.
userManager.setHost("localhost");
userManager.setPort(3050);
userManager.setUser("SYSDBA");
userManager.setPassword("masterkey");
userManager.add(user);
This chapter describes the methods declared in the MaintenanceManager interface and its
implementation, the FBMaintenanceManager class.
One of the most often used maintenance operations is database shutdown and/or bringing it back
77
Chapter 7. Working with Services
online. When the database was shutdown only the user that initiated the shutdown, either SYSDBA
or the database owner, can connect to the database and perform other tasks, e.g. metadata
modification or database validation and repair.
The database shutdown is performed by shutdownDatabase(int, int) method. The first parameter is
the shutdown mode, the second – maximum allowed time for operation.
When after the maximum allowed time for operation there are
still open connections to the database, the shutdown process is
aborted.
SHUTDOWN_TRANSACTIONAL The shutdown process is started and it is not possible to start
new transactions or open new connections to the database. The
transactions that were running at the time of shutdown initiation
are fully functional.
When after the maximum allowed time for operation there are
still running transactions, the shutdown process is aborted.
After database shutdown, the owner of the database or SYSDBA can connect to it and perform
[14]
maintenance tasks, e.g. migration to the new data model , validation of the database, changing the
database file configuration.
A database shadow is an in-sync copy of the database that is usually stored on a different hard disk,
[15]
possibly on a remote computer , which can be used as a primary database if the main database
server crashes. Shadows can be defined using CREATE SHADOW SQL command and are characterized
by a mode parameter:
• in the AUTO mode database continues operating even if shadow becomes unavailable (disk or
file system failure, remote node is not accessible, etc.)
78
Chapter 7. Working with Services
• in the MANUAL mode all database operations are halted until the problem is fixed. Usually it
means that DBA has to kill the unavailable shadow and define a new one.
Additionally, if the main database becomes unavailable, the DBA can decide to switch to the shadow
database. In this case the shadow must be activated before use. To activate the shadow use the
activateShadowFile() method. Please note, that in this case the database property of the
MaintenanceManager must point to the shadow file which must be located on the local file system of
the server to which the management class is connected.
The Firebird server does its best to keep the database file in a consistent form. In particular this is
achieved by a special algorithm called careful writes which guarantees that the server writes data
on disk in such a manner that despite events like a server crash the database file always remains in
a consistent state. Unfortunately, it is still possible that under certain conditions, e.g. crash of the
file system or hardware failure, the database file might become corrupted. Firebird server can
detect such cases including
• Orphan pages. These are the database pages that were allocated for subsequent write, but due
to a crash were not used. Such pages have to be marked as unused to return storage space back
to the application;
• Corrupted pages. These are the database pages that were caused by the operating system or
hardware failures.
The MaintenanceManager class provides a validateDatabase() method to perform simple health check
of the database, and releasing the orphan pages if needed. It also reports presence of the checksum
errors. The output of the routine is written to the output stream configured in the logger property.
79
Chapter 7. Working with Services
In order to repair the corrupted database use the markCorruptRecords() method which marks the
corrupted records as unavailable. This method is equivalent to gfix -mend command. After this
operation database can be backed up and restored to a different place.
Limbo transactions are transactions that were prepared for commit but were never committed.
This can happen when, for example, the database was accessed by JTA-enabled applications from
[16]
Java . The in-limbo transactions affect the normal database operation, since the records that were
modified in that transactions are not available – Firebird does not know whether the new version
will be committed or rolled back and blocks access to them. Also in-limbo transactions prevents
garbage collection, since the garbage collector does not know whether it can discard the record
versions of the in-limbo transaction.
Jaybird contains functionality to allow the JTA-enabled transaction coordinator to recover the in-
limbo transactions and either commit them or perform a rollback. For the cases when this is not
possible MaintenanceManager provides the following methods to perform this in interactive mode:
Method Description
listLimboTransactions() Method lists IDs of all in-limbo transactions to the output stream
specified in logger property.
The in-limbo transactions are not the only kind of transactions that prevent garbage collection.
Another type are transactions are those that were finished by "rollback" and the changes made in
such transactions were not automatically undone by the internal savepoint mechanism, e.g. when
there were a lot of changes made in the transaction (e.g. 10,000 records and more). Such
transactions are marked as "rollback" transactions on Transaction Inventory Page and this prevents
advancing the so-called Oldest Interesting Transaction (OIT) – ID of the oldest transaction which
created record versions that are relevant to any of the currently running transactions. On each
access to the records, Firebird has to check all the record versions between the current transaction
and the OIT, which leads to performance degradation on large databases. In order to solve the issue
80
Chapter 7. Working with Services
Firebird periodically starts a database sweeping process, that traverses all database records,
[17]
removes the changes made by the rolled back transactions and moves forward the OIT.
The sweep process is controlled by a threshold parameter – a difference between the Next
Transaction and OIT, by default it equal to 20,000. While this value is ok for the average database, a
DBA can decide to increase or decrease the number to fit the database usage scenario. Alternatively,
a DBA can trigger the sweep process manually regardless of the current difference between Next
Transaction and OIT.
Method Description
setSweepThreshold(int) Set the threshold between Next Transaction and OIT that will trigger the
automatic sweep process. Default value is 20,000.
sweepDatabase() Perform the sweep regardless of the current difference between Next
Transaction and OIT.
There are a few other properties of the database that can be set via MaintenanceManager:
Method Description
setDatabaseAccessMode(int) Change the access mode of the database. Possible values are:
setDatabaseDialect(int) Change the database SQL dialect. The allowed values can be
either 1 or 3.
setDefaultCacheBuffer(int) Change the number of database pages to cache.
When forced writes are switched off, the database engine does
not enforce flushing pending changes to disk and they are kept in
OS cache. Tthe same page is changed again later, the write
happens in memory, which in many cases increases the
performance. However, in case of OS or hardware crashes the
database will be corrupted.
81
Chapter 7. Working with Services
Method Description
setPageFill(int) Set the page fill factor.
The following methods provide the functionality equivalent to the gstat command line tool, the
output of the commands is written to the output stream specified in the logger property. It is the
responsibility of the application to correctly parse the text output if needed.
Method Description
getDatabaseStatistics() Get complete statistics about the database.
getDatabaseStatistics(int) Get the statistical information for the specified options.
• DATA_TABLE_STATISTICS
• SYSTEM_TABLE_STATISTICS
• INDEX_STATISTICS
• RECORD_VERSION_STATISTICS
getHeaderPage() Get information from the header page (e.g. page size, OIT, OAT
and Next transaction values, etc.)
getTableStatistics(String[]) Get statistic information for the specified tables.
[10] The output of the service is always transferred over the network regardless whether the logger property is set or not.
82
Chapter 7. Working with Services
Additionally to providing a possibility to the user to track the service progress it acts also as a signal of operation completion – in
this case the Java code will receive an EOF marker.
[11] Cooperative garbage collection can be switched off in Firebird 2.0 SuperServer architecture by corresponding configuration
option. It can’t be switched off in ClassicServer architecture and in previous Firebird versions.
[12] All versions of Firebird upto 2.5 allow to define validity constraints despite the table(s) contain data that do not satisfy them.
Only the new records will be validated, and it is responsibility of the database administrator to ensure the validity of existing ones.
[13] The class implementation is a simple bean publishing the properties via getters and setters. You can replace it with any other
implementation of the User interface.
[14] Until Firebird 2.0 adding a foreign key constraint required exclusive access to the database.
[15] Currently possible only on Unix platforms by using NFS shares.
[16] Another reason for limbo transactions are multidatabase transactions which can be initiated via native Firebird API.
However, since Jaybird does not provide methods to initiate them, we do not consider them in this manual.
[17] For more information please read article by Ann Harrison "Firebird for the Database Expert: Episode 4 - OAT, OIT, & Sweep",
available, for example, at http://www.ibphoenix.com/resources/documents/design/doc_21
83
Chapter 7. Working with Services
84
Chapter 8. Working with Events
This chapter describes the event mechanism in Firebird and the common usage scenarios.
Events are delivered to the application only on (after) commit of the transaction that generated the
event. Firebird does not provide any guarantees about the time of event delivery – it depends on
the load of the Firebird engine, application load, network delays between application and the
database system. The database engine will continue operating even if no application subscribes to
events or when the subscribed application crashed in the meantime.
It can also happen that multiple transactions will be committed before the events are delivered to
the client system. But even in such case the callback function will be invoked only once, and only
the event name and the count of the events will be passed as parameters. The same applies to
periodical polling – the application will receive event names and counts of the events since last
polling.
Internally, Firebird can be thought to store the subscription information in a table where columns
contain event names, rows correspond to the subscribed applications and the cells contain the
count of the particular event for a particular application. When an event is posted in trigger or
stored procedure, Firebird checks the subscription information and increases the event count for
the subscribed applications. Another thread checks the table periodically and notifies the
application about all new events relevant to the particular application. Such mechanism allows
[18]
Firebird to keep the event notification table very small and to reduce the number of messages
sent to the application.
It is not possible to pass parameters with the event, e.g. an ID of the modified
records. It is also not possible to encode such information in the event names –
wildcards are not supported. For such cases, applications should maintain a
change tracking table where the IDs of the modified records are stored and the
event mechanism is used to tell the application that new records were added to the
table.
85
Chapter 8. Working with Events
Firebird 2.0 introduced a new command EXECUTE BLOCK which allows to execute PSQL statements
within DSQL code:
Applications have to configure the following properties before starting use of the implementation
EventManager interface:
86
Chapter 8. Working with Events
After configuring these properties, the application has to invoke the connect() method to establish a
physical connection to the database. At this point the EventManager is ready to receive the event
notifications.
Now the application developer has two choices: use asynchronous event notification or use
methods that will block until an event is delivered or timeout occurs.
The asynchronous event notification uses a separate daemon thread to wait for the event
notifications and to deliver the events to the registered listeners. The listeners are added using the
addEventListener(String, EventListener) method, where the first parameter contains the name of
the event to register on and the second parameter – an instance of EventListener interface that will
be notified about occurrences of this event. It is allowed to use the same instance of EventListener
interface to listen on different events. The code below shows an example of using asynchronous
event notification.
eventManager.setHost("localhost");
eventManager.setUser("SYSDBA");
eventManager.setPassword("masterkey");
eventManager.setDatabase("c:/database/employee.fdb");
eventManager.connect();
eventManager.addEventListener("test_event",
new EventListener() {
public void eventOccurred(DatabaseEvent event){
System.out.println("Event [" +
event.getEventName() + "] occured " +
event.getEventCount() + " time(s)");
}
}
);
Alternatively, an application can use the synchronous methods, one that blocks until the named
event is received – the waitForEvent(String) method, or one that will block until the named event is
received or timeout specified in the second parameter occurs – the waitForEvent(String, int)
method. The following shows an example of using the blocking methods.
87
Chapter 8. Working with Events
eventManager.setHost("localhost");
eventManager.setUser("SYSDBA");
eventManager.setPassword("masterkey");
eventManager.setDatabase("c:/database/employee.fdb");
eventManager.connect();
int eventCount =
eventManager.waitForEvent("test_event", 10 * 1000);
System.out.println(
"Received " + eventCount + " event(s) during 10 sec.");
[18] For example, the effective size for 100 applications subscribed for 100 different events is about 40k in memory.
88
Reference Manual
89
90
Chapter 9. Connection reference
Firebird 3 introduced authentication plugins together with a new authentication model. By default,
Firebird 3 uses the authentication plugin Srp (Secure remote password). It also includes plugins
Legacy_Auth that supports the pre-Firebird-3 authentication mechanism, and - Since: Firebird 3.0.4 -
Srp256. Firebird 4 introduced the plugins Srp224, Srp384 and Srp512.
The original Srp plugin uses SHA-1, the new Srp-variants use SHA-224, SHA-256, SHA-384 and SHA-
[19]
512 respectively.
Support for these plugins depends on support of these hash algorithms in the JVM.
For example, SHA-224 is not supported in Oracle Java 7 by default and may require
additional JCE libraries.
Jaybird 3
Jaybird 3 will try - in order - Srp and Legacy_Auth, or - Since: Jaybird 3.0.5 - Srp256, Srp and
Legacy_Auth. It is not possible to specify a different configuration in Jaybird 3.
Jaybird 4
The default plugins applied by Jaybird 4 are - in order - Srp256 and Srp. This applies only for the
pure Java protocol and only when connecting to Firebird 3 or higher. The native implementation
will use its own default or the value configured through its firebird.conf.
When connecting to Firebird 3 or higher, the pure Java protocol in Jaybird 4 will no longer try the
Legacy_Auth plugin by default as it is an unsafe authentication mechanism. We strongly suggest to
use SRP users only, but if you really need to use legacy authentication, you can specify connection
property authPlugins=Legacy_Auth, see Configure authentication plugins for details.
When connecting to Firebird 3 versions earlier than 3.0.4, or if Srp256 has been removed from the
AuthServer setting in Firebird, this might result in slightly slower authentication because more
roundtrips to the server are needed. After an attempt to use Srp256 fails, authentication continues
with Srp.
To avoid this, consider explicitly configuring the authentication plugins to use, see Configure
authentication plugins for details.
91
Chapter 9. Connection reference
Since: Jaybird 4
Jaybird 4 introduces the connection property authPlugins (alias auth_plugin_list) to specify the
authentication plugins to try when connecting. The value of this property is a comma-separated list
with the plugin names.
Unknown or unsupported plugins will be logged and skipped. When no known plugins are
specified, Jaybird will throw an exception with:
• For native
Error occurred during login, please check server firebird.log for details [SQLState:08006, ISC error
code:335545106]
The authPlugins property only affects connecting to Firebird 3 or later. It will be ignored when
connecting to Firebird 2.5 or earlier. The setting will also be ignored for native connections when
using a fbclient library of version 2.5 or earlier.
Examples:
jdbc:firebirdsql://localhost/employee?authPlugins=Srp256
jdbc:firebirdsql://localhost/employee?authPlugins=Legacy_Auth
jdbc:firebirdsql://localhost/employee?authPlugins=Legacy_Auth,Srp512
The property is also supported by the data sources, service managers and event manager.
92
Chapter 9. Connection reference
Since: Jaybird 4
If you develop your own Firebird authentication plugin (or use a third-party authentication plugin),
it is possible - for pure Java only - to add your own authentication plugin by implementing the
interfaces
• org.firebirdsql.gds.ng.wire.auth.AuthenticationPluginSpi
• org.firebirdsql.gds.ng.wire.auth.AuthenticationPlugin
• We haven’t tested this extensively (except for loading Jaybird’s own plugins internally)
• The authentication plugin (and provider) interfaces should be considered unstable; they may
change with point-releases (although we will try to avoid that)
• For now it will be necessary for the jar containing the authentication plugin to be loaded by the
same class loader as Jaybird itself
If you implement a custom authentication plugin and run into problems, contact us on the Firebird-
Java mailing list.
If you use a native connection, check the Firebird documentation how to add third-party
authentication plugins to fbclient.
Firebird 3 and higher have support for encrypting the data sent over the network. This wire
encryption is configured using the connection property wireCrypt, with the following (case-
insensitive) values:
DEFAULT
default (value used when wireCrypt is not specified; you’d normally not specify DEFAULT
explicitly)
ENABLED
enable, but not require, wire encryption
REQUIRED
require wire encryption (only if Firebird version is 3.0 or higher)
93
Chapter 9. Connection reference
DISABLED
disable wire encryption
The default value acts as ENABLED for pure Java connections, for JNA (native) connections this wil
use the fbclient default (either Enabled or the configured value of WireCrypt from a firebird.conf
read by the native library).
Connection property wireCrypt=REQUIRED will not reject unencrypted connections when connecting
to Firebird 2.5 or lower. This behavior matches the Firebird 3 client library behavior. The value will
also be ignored when using native connections with a Firebird 2.5 client library.
Using wireCrypt=DISABLED when Firebird 3 or higher uses setting WireCrypt = Required (or vice
versa) will yield error "Incompatible wire encryption levels requested on client and server" (error:
isc_wirecrypt_incompatible / 335545064).
The same error is raised when connecting to Firebird 3 and higher with a legacy authentication
user with connection property wireCrypt=REQUIRED.
Alternative wire encryption plugins are currently not supported, although we made some
preparations to support this. If you want to develop such a plugin, contact us on the Firebird-Java
mailing list so we can work out the details of adding plugin support.
• we cannot guarantee that the session key cannot be obtained by someone with
access to your application or the machine hosting your application (although
that in itself would already imply a severe security breach)
Jaybird 4 added support for zlib wire compression in the pure Java wire protocol. Compression can
be enabled using boolean connection property wireCompression.
The connection property only has effect for the pure Java wire protocol connections on Firebird 3
and higher, if the server has the zlib library. Native connections will follow the WireCompression
configuration in the firebird.conf read by the client library, if the zlib library is on the search path.
94
Chapter 9. Connection reference
Compression is currently disabled by default. This may change in future versions of Jaybird to be
enabled by default.
The wireCompression property is also available on data sources and the management classes in
org.firebirdsql.management.
Jaybird 3.0.4 added support for Firebird 3 database encryption callbacks in the pure Java
implementation of the version 13 protocol.
The current implementation is simple and only supports replying with a static value from a
connection property. Be aware that a static value response for database encryption is not very
secure as it can easily lead to replay attacks or unintended key exposure.
Future versions of Jaybird (likely 4, maybe 5) will introduce plugin support for database encryption
plugins that require a more complex callback.
The static response value of the encryption callback can be set through the dbCryptConfig
connection property. Data sources and ServiceManager implementations have an equivalent
property with the same name. This property can be set as follows:
• Absent or empty value: empty response to callback (depending on the database encryption
plugin this may just work or yield an error later).
• Strings prefixed with base64:: rest of the string is decoded as base64 to bytes. The = padding
characters are optional, but when present they must be valid (that is: if you use padding, you
must use the right number of padding characters for the length).
• Plain string value: string is encoded to bytes using UTF-8, and these bytes are used as the
response.
Because of the limitation of connection URL parsing, we strongly suggest to avoid plain string
values with & or ;. Likewise, avoid : so that we can support other prefixes similar to base64: in the
future. If you need these characters, consider using a base64 encoded value instead.
Since: Jaybird 3.0.9 Jaybird 3.0.9 and higher expects keys and values in the JDBC URL to be URL
encoded. When the base64 encoded value contains +, it must be escaped as %2B in the JDBC URL,
otherwise it is decoded to a space and decoding will fail. For backwards compatibility with Jaybird
3, we can’t switch to the URL-safe variant of base64.
95
Chapter 9. Connection reference
• Firebird may ask for the database encryption key before the connection has
been encrypted (for example if the encrypted database itself is used as the
security database). This applies to v15 protocol support, which is not yet
available.
Specifically, such applications open a result set and, while traversing it, execute other statements
using the same connection. According to the JDBC specification the result set has to be closed if
another statement is executed using the same connection in auto-commit mode. With the default
result set holdability, close on commit, doing this yields a SQLException with message "The result set
is closed".
96
Chapter 9. Connection reference
The price for using this feature is that each holdable result set will be fully cached
in memory. The memory occupied by this result set will be released when the
statement that produced the result set is either closed or re-executed.
With this option, Jaybird will configure the transaction to use isc_tpb_autocommit with
autoCommit=true. This means that Firebird server will internally commit the transaction after each
statement completion. Jaybird itself will not commit until connection close (or switching to
autoCommit=false). The exception is if the statement was of type isc_info_sql_stmt_ddl, in that case
Jaybird will commit on statement success and rollback on statement failure (just like it does for all
statements in normal auto commit mode). The reason is that Firebird for some DDL commands only
executes at a real commit boundary and relying on the Firebird auto-commit is insufficient.
On statement completion (as specified in JDBC), result sets will still close unless they are holdable
over commit. The result set is only closed client side, which means that the cursor remains open
server side to prevent roundtrips. This may lead to additional resource usage server side unless
explicitly closed in the code. Note that any open blobs will be closed client- and server-side (until
this is improved with JDBC-401 [http://tracker.firebirdsql.org/browse/JDBC-401]).
If you manually add isc_tpb_autocommit to the transaction parameter buffer and you enable this
option, the isc_tpb_autocommit will be removed from the TPB if autoCommit=false.
Artificial testing with repeated inserts (using a prepared statement) against a Firebird server on
localhost shows that this leads to a reduction of execution time of +/- 7%.
Support for this option is experimental, and should only be enabled if you 1) know what you’re
doing, and 2) really need this feature. Internally isc_tpb_autocommit uses commit_retaining, which
means that using this feature may increase the transaction gap with associated sweep and garbage
collection impact.
Firebird 2.1 introduced the MON$ATTACHMENTS table. This table includes the columns MON$REMOTE_PID
and MON$REMOTE_PROCESS which report the process id and process name of the connected process.
By default, Jaybird does not provide this information. This has two main reasons: until recently
Java did not have a portable way of retrieving the process id, and in most cases the process name is
just 'java' (or similar), which is not very useful.
97
Chapter 9. Connection reference
Since Firebird 3, the MON$ATTACHMENTS table also includes the column MON$CLIENT_VERSION. Jaybird
(Since: Jaybird 3.0) will report its full version (eg Jaybird 3.0.5-JDK_1.8).
Do not use this information for security decisions. Treat it as informational only, as
clients can report fake information.
org.firebirdsql.jdbc.pid
Process id
org.firebirdsql.jdbc.processName
Process name
This is the preferred method because you only need to specify it once.
process_id
Process id (alias: processId (Since: Jaybird 3))
process_name
Process name (alias: processName (Since: Jaybird 3))
These properties are not exposed on the data sources. To set on data sources, use
setNonStandardProperty.
Firebird 4 (build 4.0.0.1683 or later) introduced the SET BIND statement and isc_dpb_set_bind DPB
item. This allows you to define data type conversion rules for compatibility or ease of processing
data.
This feature is specifically necessary for using the WITH TIME ZONE types under Jaybird 3, or Jaybird 4
on Java 7. See also Defining time zone data type bind.
In Jaybird this is exposed as connection property dataTypeBind (alias set_bind). The value of this
connection property is a semicolon-separated list of data type bind definitions.
A data type bind definition is of the form <from-type> TO <to-type>. A definition is the same as the
98
Chapter 9. Connection reference
second half of a SET BIND statement after the OF. See the Firebird documentation of SET BIND for
more information. Invalid values or impossible mappings will result in an error on connect.
When using the dataTypeBind connection property in a JDBC URL, the semicolons of the list need to
be encoded as %3B, as unescaped semicolons in the JDBC URL are an alternative to & as the separator
between properties.
For example:
When the property is set through a Properties object or a DataSource configuration, encoding the
semicolon is not necessary and will result in errors.
For example:
Values set through this connection property will be the session default configuration, which means
that they are retained (or reverted to) when executing ALTER SESSION RESET.
[19] Internally SrpNNN continues to uses SHA-1, only the client-proof applies the SHA-NNN hash. See also CORE-5788
[http://tracker.firebirdsql.org/browse/CORE-5788]).
99
Chapter 9. Connection reference
100
Chapter 10. Statement reference
Jaybird 2.2 added support for the getGeneratedKeys() JDBC feature for Statement and
PreparedStatement. This feature can be used to retrieve the generated ids (and other columns) from
DML statements.
2. Methods accepting an int[] parameter with column indexes, see Generated keys by column
index.
3. Methods accepting a String[] parameter with column names, see Generated keys by column
name.
In this case all of the previous cases are ignored and the query is executed as is. It is possible to
retrieve the result set using getGeneratedKeys().
The generated keys functionality will only be available if the ANTLR runtime classes are on the
classpath. Except for calling methods with NO_GENERATED_KEYS, absence of the ANTLR runtime will
throw FBDriverNotCapableException.
The required ANTLR runtime version depends on the Jaybird version, check the
release notes of your version for details.
This functionality is available for INSERT (Since: Firebird 2.0), for UPDATE, UPDATE OR INSERT and
DELETE (Since: Firebird 2.1), and for MERGE (Since: Firebird 3.0).
101
Chapter 10. Statement reference
When RETURN_GENERATED_KEYS is passed, the driver will return all columns of the table as generated
keys. The columns are ordered by ordinal position (as reported in the JDBC metadata of the table). It
is advisable to retrieve the values from the getGeneratedKeys() result set by column name.
We opted to include all columns as it is next to impossible to decide which columns are populated
by a trigger or otherwise. Only returning the primary key will be too restrictive (consider computed
columns, default values, etc).
Passing NO_GENERATED_KEYS hardcoded should normally not be done. It would be better to use the
equivalent prepareStatement or executeXXX method that only accepts a String. Use of the value
NO_GENERATED_KEYS only makes sense in code that dynamically decides between NO_GENERATED_KEYS
and RETURN_GENERATED_KEYS.
The following will insert a person using a Statement and retrieve the generated id using
Statement.RETURN_GENERATED_KEYS:
102
Chapter 10. Statement reference
③ Just like a normal result set, it is positioned before the first row, so you need to call next()
⑥ The generated keys result set also contains the normal columns like FIRSTNAME
103
Chapter 10. Statement reference
statement.executeUpdate();
try (ResultSet keys = statement.getGeneratedKeys()) { ②
if (keys.next()) { ③
int generatedId = keys.getInt("id"); ④
int age = keys.getInt("age"); ⑤
String firstName = keys.getString("firstname");
The values in the int[] parameter are the ordinal positions of the columns as specified in the (JDBC)
metadata of the table.
104
Chapter 10. Statement reference
In Jaybird 3 and earlier, a null or empty array was silently ignored and the
statement was executed normally (not producing generated keys). In Jaybird 4, this
behaviour has changed and instead will throw an exception with message
"Generated keys array columnIndexes was empty or null. A non-empty array is
required."
In Jaybird 3 and earlier, invalid ordinal positions are ignored and silently dropped:
passing new int[] { 1, 5, 6 } will work, even though we don’t have sixth column.
In Jaybird 4, this behavior has changed and instead will throw an exception with
message "Generated keys column position <position> does not exist for table
<tablename>. Check DatabaseMetaData.getColumns (column ORDINAL_POSITION)
for valid values."
1. ID
2. FIRSTNAME
3. LASTNAME
4. BIRTHDATE
5. age
statement.executeUpdate();
try (ResultSet keys = statement.getGeneratedKeys()) {
if (keys.next()) {
int generatedId = keys.getInt("id"); ②
int age = keys.getInt(2); ③
105
Chapter 10. Statement reference
③ Retrieval of the second column, age, by id. Notice that the index used for retrieval does not
match the position (5) passed in the prepare. As this is the second column, it is retrieved from
the result set by 2.
In Jaybird 3 and earlier, the array of indices is sorted in ascending order before
use: passing new int[] { 4, 1, 3 } will yield columns in order ID, LASTNAME,
BIRTHDATE. In Jaybird 4, this sort is no longer applied, so columns will be in the
order specified by the array: BIRTHDATE, ID, LASTNAME. To avoid issues, we
recommend specifying the columns in ascending order, or always retrieve them by
name.
The values in the String[] are the column names to be returned. The column names provided are
processed as is and are not checked for validity or the need of quoting. Providing non-existent or
incorrectly (un)quoted columns will result in an exception when the statement is processed by
Firebird (be aware: the JDBC specification is not entirely clear if this is valid behavior, so this might
change in the future). This method is the fastest as it does not retrieve metadata from the server.
In Jaybird 3 and earlier, a null or empty array was silently ignored and the
statement was executed normally (not producing generated keys). In Jaybird 4, this
behaviour has changed and instead will throw an exception with message
"Generated keys array columnNames was empty or null. A non-empty array is
required."
106
Chapter 10. Statement reference
statement.executeUpdate();
try (ResultSet keys = statement.getGeneratedKeys()) {
if (keys.next()) {
int generatedId = keys.getInt("id");
int age = keys.getInt("age");
① The column names are passed as is, this means that correct quoting is required for case sensitive
columns (and other names that require quoting).
The requirement to pass column names correctly quoted is not specified in the
JDBC standard. It may change in future Jaybird versions to conform with column
names as returned from DatabaseMetaData.getColumn. That is, unquoted exactly as
stored in RDB$RELATION_FIELDS.RDB$FIELD_NAME. Quoting the column names would
then be done by Jaybird.
Since: Jaybird 4
• default: default behaviour to enable generated keys for statement types with RETURNING clause in
the connected Firebird version. Absence of this property, null or empty string implies default.
• disabled: disable support. Attempts to use generated keys methods other than using
Statement.NO_GENERATED_KEYS will throw a SQLFeatureNotSupportedException.
• ignored: ignore generated keys support. Attempts to use generated keys methods will not
attempt to detect generated keys support and execute as if the statement generates no keys. The
Statement.getGeneratedKeys() method will always return an empty result set. This behaviour is
107
Chapter 10. Statement reference
Because of the behaviour specified in the next section, typos in property values will behave as
ignored (eg using generatedKeysEnabled=disable instead of disabled will behave as ignored).
This last option allows you to selectively enable support for generated keys. For example,
generatedKeysEnabled=insert will only enable it for insert while ignoring it for all other statement
types. Statement types that are not enabled will behave as if they generate no keys and will execute
normally. For these statement types, Statement.getGeneratedKeys() will return an empty result set.
• insert
• update
• delete
• update_or_insert
• merge
Invalid values will be ignored. If none of he specified statement types are supported by Firebird, it
[20]
will behave as ignored.
Some examples:
This feature can be used to circumvent issues with frameworks or tools that always use generated
keys methods for prepare or execution. For example with UPDATE statements that touch multiple
records and - given the Firebird limitations for RETURNING - produce the error "multiple rows in
singleton select".
10.1.5. Limitations
Jaybird 2.2 does not support generated keys retrieval for batch execution of prepared statements.
Support for generated key retrieval with batch execution was introduced in Jaybird 3.0.
108
Chapter 10. Statement reference
On Firebird 2.1 and higher, Jaybird will use the procedure type information from the database
metadata to decide how to execute CallableStatement. When a procedure is selectable, Jaybird will
automatically transform a call-escape or EXECUTE PROCEDURE statement to a SELECT.
In some cases this automatic transformation to use a SELECT leads to problems. You can explicitly set
FirebirdCallableStatement.setSelectableProcedure(false) to fix most of these issues, but this is not
always an option. For example spring-data-jpa’s @Procedure will not work correctly with selectable
procedures, but you can’t call setSelectableProcedure.
To disable this automatic usage of procedure type information, set connection property
ignoreProcedureType=true. When necessary you can use
FirebirdCallableStatement.setSelectableProcedure(true) to execute a procedure using SELECT.
Be aware though, when EXECUTE PROCEDURE is used with a selectable procedure, it is executed only
up to the first SUSPEND, and the rest of the stored procedure is not executed.
For Firebird 2.0 and lower this property has no effect, as there the procedure type information is
not available.
[20] This is not the case for the unsupported Firebird 1.0 and 1.5 versions. There this will behave similar to disabled, and you will
need to explicitly specify ignored instead to get this behaviour.
109
Chapter 10. Statement reference
110
Chapter 11. General
warn warnings
error errors
11.1.1. java.util.logging
Since: Jaybird 3
Since: Jaybird 3
Jaybird can write its logging to the System.out for info and lower and System.err for warn and
111
Chapter 11. General
Since: Jaybird 3
Since Jaybird 3, you can provide your own logging implementation if you don’t want to use
java.util.logging or console logging.
For example:
package org.example.jaybird.logging;
-Dorg.firebirdsql.jdbc.loggerImplementation=org.example.jaybird.logging.CustomLogger
Jaybird 2.2 and earlier can log to Log4J 1.x. This requires the log4j 1.x library on the classpath and
system property FBLog4j (or Since: Jaybird 2.2.8 org.firebirdsql.jdbc.useLog4j) set to true.
If you want to use Log4j 1.x with Jaybird 3 or higher, you will need to create your own logger
implementation (see Custom logging implementation).
112
Chapter 12. Datatype reference
Since: Firebird 4 Firebird 4 introduces the names BINARY and VARBINARY/BINARY VARYING as aliases for
(VAR)CHAR(n) CHARACTER SET OCTETS.
In Java binary and varbinary are usually handled with byte arrays and InputStream/OutputStream.
In Jaybird 2.2 and earlier, the default for (VAR)CHAR(n) CHARACTER SET OCTETS is to handle columns
and parameters of this type as a string. That is, getObject(int/String) returns String, and metadata
reports (VAR)CHAR type information. The bytes are converted to string using the default encoding or
the connection encoding.
Jaybird 2.1.1 introduced the boolean connection property octetsAsBytes. When set,
getObject(int/String) will return byte[], but otherwise columns or parameters will behave as
normal string fields. Metadata information from sources like DatabaseMetaData, ParameterMetaData,
and ResultSetMetaData, will report information as if it is a String ((VAR)CHAR) based field. Since:
Jaybird 2.2.9 ResultSetMetaData reports (VAR)BINARY type information.
Since: Jaybird 3
Jaybird 3 and higher no longer handle (VAR)CHAR(n) CHARACTER SET OCTETS as JDBC types CHAR
/VARCHAR, but always as BINARY/VARBINARY. This closer matches their intended usage. The connection
property octetsAsBytes is no longer supported.
Jaybird will report the JDBC BINARY/VARBINARY type information in all metadata (DatabaseMetaData,
ResultSetMetaData, ParameterMetaData) for columns and parameters of type (VAR)CHAR(n) CHARACTER
SET OCTETS, and getObject(int/String) will always return byte[].
The getters (on result set/callable statement), setters (prepared/callable statement), and update
methods (result set) for columns of this type are restricted to:
113
Chapter 12. Datatype reference
• get/set/updateNull
• get/set/updateBytes
• get/set/updateBinaryStream
• get/set/updateAsciiStream
Other getters/setters/updaters or object types supported for 'normal' (VAR)CHAR fields are not
available.
On parameters of type BOOLEAN, Jaybird supports most of the other Java types, using the following
mapping:
integer types 0 sets false, everything else sets true true is 1, false is 0
float Exact 0.0f sets false, everything else true is 1.0f, false is 0.0f
[21]
sets true
double Exact 0.0 sets false, everything else true is 1.0, false is 0.0
[21]
sets true
BigDecimal 0 (ZERO) (using compareTo) sets false, true is 1 (ONE), false is 0 (ZERO)
everything else sets true
114
Chapter 12. Datatype reference
Firebird 2.5 and earlier do not support BOOLEAN, but support for booleans can be simulated
• Use CHAR or VARCHAR with length 5 or longer with values 'true' and 'false'
We recommend creating a domain for 'simulated' booleans with a check constraint to restrict the
possible values. If you do this, name the domain something like D_BOOLEAN, and avoid the name
BOOLEAN to prevent problems when upgrading to Firebird 3.
For non-boolean types, Jaybird supports the following conversions with setBoolean and getBoolean:
(VAR)CHAR(<5) 'Y'/'T'/'1'/'true' is true (case true sets 'Y', false sets 'N'
insensitive), everything else is false
(VAR)CHAR(>=5) 'Y'/'T'/'1'/'true' is true (case true sets 'true', false sets 'false'
insensitive), everything else is false
BLOB SUB_TYPE TEXT 'Y'/'T'/'1'/'true' is true (case true sets 'true', false sets 'false'
insensitive), everything else is false
REAL/FLOAT Exact 1.0f is true, everything else is true sets 1.0f, false sets 0.0f
[22]
false
DOUBLE PRECISION Exact 1.0 is true, everything else is true sets 1.0, false sets 0.0
[22]
false
DECFLOAT Exact 1E0 is true, everything else is true sets 1E0, false sets 0E0
[23]
false (including 1.0E0!)
We recommend to avoid the DECIMAL, NUMERIC, REAL/FLOAT, DOUBLE PRECISION or DECFLOAT options.
Since: Firebird 4
Firebird 4 introduced time zone types, with types TIME WITH TIME ZONE and TIMESTAMP WITH TIME
ZONE. See the Firebird 4 release notes and doc/sql.extensions/README.time_zone.md in the Firebird
installation for details on these types.
115
Chapter 12. Datatype reference
Since: Jaybird 4
Since Jaybird 4, the time zone types are supported under Java 8 and higher, using the Java 8 (or
higher) version of Jaybird. Time zone types are not supported under Java 7, and you will need to
enable legacy time zone bind to use these types. With legacy time zone bind, Firebird will convert
to the equivalent TIME and TIMESTAMP (WITHOUT TIME ZONE) types using the session time zone. Time
zone binds can be configured with connection property dataTypeBind, for more information see
Defining time zone data type bind.
Since: Jaybird 4
JDBC 4.2 introduced support for time zones, and maps these types to java.time.OffsetTime and
java.time.OffsetDateTime. JDBC does not define explicit setters for these types. Use setObject(index,
value), updateObject(index, value), getObject(index/name) or getObject(index/name, classType).
Firebird 4 supports both offset and named time zones. Given the definition in JDBC, Jaybird defaults
to offset time zones. On retrieval of a value with a named zone, Jaybird will make a best effort to
convert to the equivalent offset using Java’s time zone information. If no mapping is available the
time will be returned at UTC (offset zero).
Jaybird 4 supports the following Java types on fields of time zone types (those marked with * are
not defined in JDBC)
◦ On get, if the value is a named zone, it will derive the offset using the base date 2020-01-01
(in 4.0.0 it used the current date). The offset can be different from the offset of the
OffsetDateTime for the same value.
• java.time.OffsetDateTime
▪ For a named zone, the time in the zone is derived at 2020-01-01 and then rebased to the
current date. As a result, the offset can be different from an OffsetTime.
◦ On get the time in the zone is derived at 2020-01-01 and then rebased to the current date.
◦ On set, the time is rebased to 2020-01-01 and then the date information is removed.
116
Chapter 12. Datatype reference
• java.lang.String
◦ On set tries the default parse format of either OffsetTime or OffsetDateTime (eg
13:25:13.1+01:00 or 2019-03-10T13:25:13+01:00) and then sets as that type
• java.sql.Time (*)
◦ On get obtains java.time.OffsetDateTime, converts this to epoch milliseconds and uses new
java.sql.Time(millis)
◦ On set applies toLocalTime(), combines this with LocalDate.now() and then derives the offset
time for the default JVM time zone
• java.sql.Timestamp (*)
◦ On get obtains java.time.OffsetDateTime, converts this to epoch milliseconds and uses new
java.sql.Timestamp(millis)
◦ On set applies toLocalDateTime() and derives the offset time for the default JVM time zone
• java.time.OffsetTime (*)
• java.lang.String
◦ On set tries the default parse format of either OffsetTime or OffsetDateTime (eg
13:25:13.1+01:00 or 2019-03-10T13:25:13+01:00) and then sets as that type
• java.sql.Time (*)
◦ On get obtains java.time.OffsetDateTime, converts this to epoch milliseconds and uses new
java.sql.Time(millis)
◦ On set applies toLocalTime(), combines this with LocalDate.now() and then derives the offset
date time for the default JVM time zone
• java.sql.Timestamp (*)
◦ On get obtains java.time.OffsetDateTime, converts this to epoch milliseconds and uses new
java.sql.Timestamp(millis)
◦ On set applies toLocalDateTime() and derives the offset date time for the default JVM time
zone
• java.sql.Date (*)
◦ On get obtains java.time.OffsetDateTime, converts this to epoch milliseconds and uses new
java.sql.Date(millis)
◦ On set applies toLocalDate() at start of day and derives the offset date time for the default
JVM time zone
117
Chapter 12. Datatype reference
In addition, Firebird 4 has 'bind-only' data types EXTENDED TIME/TIMESTAMP WITH TIME ZONE. These
data types can be set through the data type bind configuration and include an extra offset in its
data so clients without access to ICU or other time zone data can use the offset as determined by
Firebird.
Jaybird provides minimal support for these types by handling them the same as the normal WITH
TIME ZONE types. That means the extra offset information is ignored and Jaybird will always use the
Java time zone information to calculate the offset of a named zone, and if a zone is unknown in
Java, Jaybird will fallback to UTC even when the actual offset is available in the 'extended' time
zone type.
See also:
For the WITH TIME ZONE types, JDBC does not define support for the legacy JDBC types (java.sql.Time,
java.sql.Timestamp and java.sql.Date). To ease the transition and potential compatibility with tools
and libraries, Jaybird does provide support. However, we strongly recommend to avoid using these
types.
Compared to the WITHOUT TIME ZONE types, there may be small discrepancies in values as Jaybird
uses 1970-01-01 for WITHOUT TIME ZONE, while for WITH TIME ZONE it uses the current date. If this is
problematic, then either apply the necessary conversions yourself, enable legacy time zone bind, or
define or cast your columns to TIME or TIMESTAMP.
Jaybird also does not support non-standard extensions like java.time.Instant. If there is interest,
we may add them in the future.
Jaybird 3.0.9 added the connection property dataTypeBind to defining data type mappings. This can
be used to configure conversion of WITH TIME ZONE types to a different datatype. When configured,
Firebird will present columns or parameters of TIME(STAMP) WITH TIME ZONE as the specified type,
allowing clients without support for WITH TIME ZONE to read or set values.
118
Chapter 12. Datatype reference
This property needs to be explicitly set if you are using Jaybird 4 on Java 7 or Jaybird 3 (on any Java
version), and need to handle the WITH TIME ZONE types. It can also be used for tools or applications
that expect java.sql.Time/Timestamp types and cannot use the java.time.OffsetTime/OffsetDateTime
types returned for the WITH TIME ZONE types.
To map TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE to the legacy without time zone types,
you can use:
Instead of legacy, you can also explicitly specify time and timestamp respectively.
Firebird will convert a WITH TIME ZONE type to the equivalent WITHOUT TIME ZONE type using the
session time zone to derive the value.
Result set columns and parameters on prepared statements will behave as the equivalent WITHOUT
TIME ZONE types. This conversion is not applied to the database metadata which will always report
WITH TIME ZONE information.
The TIME ZONE TO EXTENDED binds (including type-specific variants) is only supported under Java 8
and higher using the Java 8 or higher version of Jaybird. As mentioned earlier, the support for
'extended' time zone types will behave identical to the normal time zone types.
This feature requires Firebird 4 beta 2 or higher (or a snapshot build version
4.0.0.1683 or later). It will be ignored in builds before 1481 as the necessary
database parameter buffer item does not exist, and it will raise an error in
versions between 1481 and 1682 as there the DPB item points to the removed DPB
item isc_time_zone_bind.
2. specifies the time zone to use when converting values of without time zone types to the legacy
JDBC datetime types on all Firebird versions (Since: Jaybird 4).
See Firebird 4 session time zone for information on the effects of sessionTimeZone on the server-
side.
Valid values are time zone names known by Firebird, we recommend to use the long names (eg
Europe/Amsterdam) and not the ambiguous short IDs (eg CET). Although not required, we recommend
to use time zone names that are known by Firebird and Java (see Session time zone for conversion
119
Chapter 12. Datatype reference
for caveats).
In Jaybird 3, sessionTimeZone will only configure the server-side session time zone. Client-side,
Jaybird will continue to use the JVM default time zone for parsing the without time zone values to
the java.sql.Time/Timestamp/Date types. Setting sessionTimeZone to the JVM default time zone will
yield the best (ie correct) values, but not setting it (and thus using the server default) will retain
behaviour that is backwards compatible with behaviour of previous versions of Jaybird. In Jaybird
4, this property also configures client-side parsing of values to these legacy types.
By default, Jaybird 4 and higher will use the JVM default time zone as reported by
java.util.TimeZone.getDefault().getID() as the session time zone. Using the JVM default time zone
as the default is the best option in the light of JDBC requirements with regard to java.sql.Time and
java.sql.Timestamp using the JVM default time zone.
To use the default server time zone and the Jaybird 3 and earlier behaviour to use the JVM default
time zone, set the connection property to server. This will result in the conversion behaviour of
Jaybird 3 and earlier. Be aware that this is inconsistent if Firebird and Java are in different time
zones.
The session time zone is used for conversion between WITH TIME ZONE values and WITHOUT TIME ZONE
values (ie using cast or with legacy time zone bind), and for the value of LOCALTIME, LOCALTIMESTAMP,
CURRENT_TIME and CURRENT_TIMESTAMP, and other uses of the session time zone as documented in the
Firebird 4 documentation.
The value of sessionTimeZone must be supported by Firebird 4. It is possible that time zone
identifiers used by Java are not supported by Firebird. If Firebird does not know the session time
zone, error (Invalid time zone region: <zone name>) is reported on connect.
In Jaybird 4 and higher, Jaybird will apply the JVM default time zone as the default session time
zone. The use of the JVM default time zone as the default session time zone will result in subtly
different behaviour compared to previous versions of Jaybird and - even with Jaybird 4 - Firebird 3
or earlier, as current time values like LOCALTIMESTAMP (etc) will now reflect the time in the JVM time
zone, and not the server time zone rebased on the JVM default time zone.
Other examples include values generated in triggers and default value clauses.
120
Chapter 12. Datatype reference
Since: Jaybird 4
For WITHOUT TIME ZONE types, the session time zone will be used to derive the java.sql.Time,
java.sql.Timestamp and java.sql.Date values. This is also done for Firebird 3 and earlier.
If Java does not know the session time zone, no error is reported, but when retrieving
java.sql.Time, java.sql.Timestamp or java.sql.Date a warning is logged and conversion will happen
in GMT, which might yield unexpected values.
For WITH TIME ZONE types, the session time zone has no effect on the conversion to the legacy JDBC
date/time types: the offset date/time is converted to epoch milliseconds and used to construct these
legacy types directly.
Executing SET TIME ZONE <zone name> statements after connect will change the session time zone on
the server, but Jaybird will continue to use the session time zone set in the connection property for
these conversions.
Although not defined in JDBC (or ODBC), Jaybird has added a non-standard extension to the CONVERT
JDBC escape to allow conversion to the time zone types.
In addition to the standard-defined types, it also supports the type names TIME_WITH_TIME_ZONE,
TIME_WITH_TIMEZONE, TIMESTAMP_WITH_TIME_ZONE and TIMESTAMP_WITH_TIMEZONE (and the same with the
SQL_ prefix).
• Firebird 4 redefines CURRENT_TIME and CURRENT_TIMESTAMP to return a WITH TIME ZONE type. Use
LOCALTIME and LOCALTIMESTAMP (introduced in Firebird 3.0.4) if you want to ensure a WITHOUT TIME
ZONE type is used.
• The database metadata will always return JDBC 4.2 compatible information on time zone types,
even on Java 7, and even when legacy time zone bind is set. For Java 7 compatibility the JDBC
4.2 java.sql.Types constants TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE are also defined in
org.firebirdsql.jdbc.JaybirdTypeCodes.
• ([.since]_Jaybird 4) The default sessionTimeZone is set to the JVM default time zone, this may
result in different application behavior for DATE, TIME and TIMESTAMP, including values generated
in triggers and default value clauses. To prevent this, either switch those types to a WITH TIME
ZONE type, or set the sessionTimeZone to server or to the actual time zone of the Firebird server.
• As CURRENT_TIME uses the session time zone, which usually is a named zone, use in combination
with java.time.OffsetTime can yield confusing results. For example, if the current date and time
is '2020-07-01T14:51:00 Europe/Amsterdam', then retrieving CURRENT_TIME as an OffsetTime will
121
Chapter 12. Datatype reference
• Overall, using TIME WITH TIME ZONE with named zones is rather fragile and prone to
interpretation errors. This is a result of how this is implemented in Firebird: values are stored
at UTC with their offset or named zones, where derivation of the time in the named zone needs
to use 2020-01-01 as the date for the time zone rules to apply.
We recommend avoiding TIME WITH TIME ZONE where possible.
Firebird 4 introduces the SQL:2016 DECFLOAT datatype, a decimal floating point with a precision of
16 or 34 digits (backed by an IEEE-754 Decimal64 or Decimal128). See the Firebird 4 documentation
for details on this datatype.
Since: Jaybird 4
Jaybird 4 introduces support for the DECFLOAT datatype mapping to java.math.BigDecimal. For more
information, see DECFLOAT support.
Jaybird 3 does not support DECFLOAT, but starting with Jaybird 3.0.9, the connection property
dataTypeBind can be used to convert to a datatype that is supported by Jaybird. For earlier Jaybird 3
versions, see Workarounds for Jaybird 2.2 and earlier.
Jaybird 2.2 and earlier do not support DECFLOAT. As a workaround, you can use the SET BIND OF
DECFLOAT TO <target-type> statement to configure your connection to map DECFLOAT to a different
datatype. When set, Firebird will present columns or parameters of DECFLOAT as the specified type,
allowing clients without support for DECFLOAT to read or set values.
The available options are the same as documented in Defining decfloat data type bind
For example
122
Chapter 12. Datatype reference
The effect of the SET BIND statement will be reset to the default when ALTER SESSION
RESET is executed.
Jaybird 3.0.9 added the connection property dataTypeBind to defining data type mappings. This can
be used to configure conversion of DECFLOAT to a different datatype. When set Firebird will present
columns or parameters of DECFLOAT as the specified type, allowing clients without support for
DECFLOAT to read or set values.
This property is also available in Jaybird 4, but we recommend to not use this
property in Jaybird 4 and instead rely on the default behaviour (native) and
support for DECFLOAT.
This feature requires Firebird 4 beta 2 or higher (or a snapshot build version
4.0.0.1683 or later). It will be ignored in builds before 1481 as the necessary
database parameter buffer item does not exist, and it will raise an error in
versions between 1481 and 1682 as there the DPB item points to the removed DPB
item isc_time_zone_bind.
To map DECFLOAT(16) to DOUBLE PRECISION and DECFLOAT(34) to string, you can use:
Firebird will convert a DECFLOAT type to the specified type using a cast to derive the value.
Result set columns and parameters on prepared statements will behave as the defined type. This
conversion is not applied to the database metadata which will always report DECFLOAT information.
123
Chapter 12. Datatype reference
In general, we recommend binding to VARCHAR as this will allow you to get (and set) the full range of
DECFLOAT values with precision.
Since: Jaybird 4
Jaybird 4 introduces support for the DECFLOAT datatype. The 'default' object type for DECFLOAT is a
java.math.BigDecimal, but conversion from and to the following datatypes is supported:
The DECFLOAT type is not yet defined in the JDBC specification. For the time being, Jaybird defines a
Jaybird specific type code with value -6001. This value is available through constant
org.firebirdsql.jdbc.JaybirdTypeCodes.DECFLOAT, or - for JDBC 4.2 and higher -
org.firebirdsql.jdbc.JaybirdType.DECFLOAT, which is an enum implementing java.sql.SQLType.
If you need to use the type code, we suggest you use these constants. If a DECFLOAT type constant gets
added to the JDBC standard, we will update the value. The enum value will be deprecated when
that version of JDBC has been released.
The DECFLOAT datatype supports values with a precision of 16 or 34 decimal digits, and an exponent
[24]
between -398 and 369 (DECFLOAT(16)), or between -6176 and 6111 (DECFLOAT(34)), so the minimum
and maximum values are:
124
Chapter 12. Datatype reference
When converting values from Java types to DECFLOAT and retrieving DECFLOAT values as Decimal32 or
Decimal64, the following rules are applied:
• Zero values can have a non-zero exponent, and if the exponent is out of range, the exponent
value is 'clamped' to the minimum or maximum exponent supported. This behavior is subject to
change, and future releases may 'round' to exact 0 (or 0E0)
• Values with a precision larger than the target precision are rounded to the target precision
using RoundingMode.HALF_EVEN
• If the magnitude (or exponent) is too low, then the following steps are applied:
2. If after the previous step, the magnitude is still too low, we have what is called an underflow,
and the value is truncated to 0 with the minimum exponent and preserving sign, eg for
DECFLOAT(16), the value will become +0E+398 or -0E-398 (see note 19). Technically, this is just
a special case of the previous step.
• If the magnitude (or exponent) is too high, then the following steps are applied:
1. If the precision is less than maximum precision, and the difference between maximum
precision and actual precision is larger than or equal to the difference between the actual
exponent and the maximum exponent, then the precision is increased by adding zeroes as
least-significant digits and decreasing the exponent by the number of zeroes added.
15
If we multiply the coefficient by 10 and subtract 15 from the exponent we get: coefficient =
15
1 * 10 = 1000000000000000 and exponent = 384 - 15 = 369. And these values for coefficient
125
Chapter 12. Datatype reference
2. Otherwise, we have what is called an overflow, and an SQLException is thrown as the value is
out of range.
If you need other rounding and overflow behavior, make sure you round the values appropriately
before you set them.
To configure the server-side(!) error and rounding behaviour of the DECFLOAT data types, you can
configure use the following connection properties:
Possible values: ceiling, up, half_up (default), half_even, half_down, down, floor, reround
Configuring these options does not change driver behaviour, only server-side behaviour.
Notes
1. Firebird 4 snapshots currently allow storing NaN and Infinity values, retrieval of these
values will result in a SQLException, with a DecimalInconvertibleException cause with details
on the special. The support for these special values is currently under discussion and may be
removed in future Firebird 4 snapshots.
2. byte in Java is signed, and historically Jaybird has preserved sign when storing byte values, and
it considers values outside -128 and +127 out of range.
3. All integral values are - if within range - first converted to long using BigDecimal.longValue(),
which discards any fractional parts (rounding by truncation).
4. When storing a long in DECFLOAT(16), rounding will be applied using RoundingMode.HALF_EVEN for
values larger than 9999999999999999L or smaller than -9999999999999999L.
5. float values are first converted to (or from) double, this may lead to small rounding differences
6. float and double can be fully stored in DECFLOAT(16) and DECLOAT(34), with minor rounding
differences.
126
Chapter 12. Datatype reference
7. When reading DECFLOAT values as double or float, rounding will be applied as binary floating
point types are inexact, and have a smaller precision.
8. If the magnitude of the DECFLOAT value is too great to be represented in float or double, +Infinity
or -Infinity may be returned (see BigDecimal.doubleValue()). This behavior is subject to change,
future releases may throw a SQLException instead, see also related note 9.
9. Storing and retrieving values NaN, +Infinity and -Infinity are currently supported, but this may
change as this doesn’t seem to be allowed by the SQL:2016 standard.
It is possible that Jaybird or Firebird will disallow storing and retrieving NaN and Infinity
values in future releases, causing Jaybird to throw an SQLException instead. We strongly suggest
not to rely on this support for special values.
1. Firebird DECFLOAT currently discerns four different NaNs (+/-NaN and +/-signaling-NaN).
These are all mapped to Double.NaN (or Float.NaN), Java NaN values are mapped to +NaN in
Firebird.
10. Setting boolean values will set 0 (or 0E+0) for false and 1 (or 1E+0) for true.
11. Retrieving as boolean will return true for 1 (exactly 1E+0) and false for all other values. Be
aware that this means that 1.0E+0 (or 10E-1) etc will be false (this may change before Jaybird 4
final to getLong() == 1L or similar, which truncates the value).
This behavior may change in the future and only allow 0 for false and exactly 1 for true and
throw an SQLException for all other values, or maybe true for everything other than 0. In general
we advise to not use numerical types for boolean values, and especially not to retrieve the
result of a calculation as a boolean value. Instead, use a real BOOLEAN.
12. Setting values as String is supported following the format rules of new BigDecimal(String), with
extra support for special values +NaN, -NaN, +sNaN, -sNaN, +Infinity and -Infinity (case
insensitive). Other non-numerical strings throw an SQLException with a NumberFormatException as
cause. Out of range values are handled as described in Precision and range.
13. Getting values as String will be equivalent to BigDecimal.toString(), with extra support for the
special values mentioned in the previous note.
14. As mentioned in earlier notes, support for the special values is under discussion, and may be
removed in the final Jaybird 4 or Firebird 4 release, or might change in future versions.
15. Getting as BigInteger will behave as BigDecimal.toBigInteger(), which discards the fractional
part (rounding by truncation), and may add (-1 * scale - precision) least-significant zeroes if
the scale exceeds precision. Be aware that use of BigInteger for large values may result in
significant memory consumption.
16. Setting as BigInteger will lose precision for values with more digits than the target type. It
applies the rules described in Precision and range.
17. Values can also be set and retrieved as types Decimal32, Decimal64 and Decimal128 from the
org.firebirdsql.extern.decimal package. Where Decimal64 exactly matches the DECFLOAT(16)
protocol format, and Decimal128 the DECFLOAT(34) protocol format. Be aware that this is an
implementation detail that might change in future Jaybird versions (both in terms of support
for these types, and in terms of the interface (API) of these types).
127
Chapter 12. Datatype reference
19. Zero values can have a sign (eg -0 vs 0 (+0)), this can only be set or retrieved using String or the
DecimalXX types, or the result of rounding. This behaviour is subject to change, and future
releases may 'round' to 0 (aka +0).
In Firebird 3 and earlier, the maximum precision of DECIMAL and NUMERIC is 18 with a maximum
[25]
scale of 18.
Since: Firebird 4 Since: Jaybird 4 In Firebird 4 the maximum precision and scale of DECIMAL and
NUMERIC have been raised to 38. Any NUMERIC or DECIMAL with a precision between 19 and 38 will
allow storage up to a precision of 38.
Values set on a field or parameter will be rounded to the target scale of the field using
RoundingMode.HALF_EVEN. Values exceeding a precision of 34 after rounding will be rejected with a
TypeConversionException.
Firebird 4 introduced the non-standard type INT128, a signed 128 bit number.
Jaybird 4.0.1 introduced support for the INT128 type. Jaybird 4.0.0 will also be able to handle the
type, but does not formally identify it as INT128.
128
Chapter 12. Datatype reference
As JDBC does not define an INT128 type, Jaybird maps the Firebird type INT128 to the JDBC type
NUMERIC with precision of 38. This way most tools should be able to handle the full range of values of
without issue.
[21] This behaviour may change in a future version to the equivalent of setLong((long) value)
[22] This behaviour may change in a future version to the equivalent of getLong(..) == 1L
[23] This behaviour may change in a future version to use compareTo or the equivalent of getLong(..) == 1L instead
[24] The DECFLOAT decimal format stores values as sign, integral number with 16 or 34 digits, and an exponent. This is similar to
java.math.BigDecimal, but instead of an exponent, that uses the concept scale, where scale = -1 * exponent.
[25] In practice, values with precision 19 are possible up to the maximum value of the BIGINT backing the value.
129
Chapter 12. Datatype reference
130
Appendices
131
132
Appendix A: Extended connection properties
This appendix provides a list of most connection properties and a short explanation to each of
them. The properties listed below are usable as JDBC connection properties.
The properties marked as boolean property can be included in the JDBC URL with values true, but
also without a value, or with an empty value. The default for these properties is always false. For
readability we suggest that you only specify these properties explicitly when you want to enable
them, and if you do, to use explicit value true.
133
Appendix A: Extended connection properties
charSet Jaybird specific property. Character set for the connection using
localEncoding Java character set name. Similar to the previous property,
however instead of Firebird-specific name allows using a Java
character set name.
134
Appendix A: Extended connection properties
socketBufferSize Jaybird specific property. Tells Jaybird Type 4 driver the size of
socket_buffer_size the socket buffer. Should be used on the systems where default
socket buffer provided by JVM is not correct.
blobBufferSize Jaybird specific property. Tells the driver the size of the buffer
blob_buffer_size that is used to transfer BLOB content. It is recommended to keep
the value equal to n * <database page size> (and preferably also
socket buffer size).
soTimeout Jaybird specific property. Socket blocking timeout in
milliseconds. Only has effect on Type 4 (pure Java) connections.
connectTimeout Connect timeout in seconds (Since: Jaybird 2.2.2). For the Java
connect_timeout, wire protocol the connect timeout will detect unreachable hosts.
isc_dpb_connect_timeout In the JNI/JNA implementation (native protocol) the connect
timeout works as the DPB item isc_dpb_connect_timeout which
only works after connecting to the server for the op_accept phase
of the protocol. This means that – for the native protocol – the
connect timeout will not detect unreachable hosts within the
timeout.
wireCompression Jaybird specific property (Since: Jaybird 4 Since: Firebird 3).
Boolean property. Set property to true to enable zlib wire
compression. See Wire compression for more information.
columnLabelForName Jaybird specific property (Since: Jaybird 2.2.1). Boolean property.
Set property to true for backwards compatible behaviour
(getColumnName() returns the column label). Don’t set the property
or set it to false for JDBC-compliant behaviour (recommended).
135
Appendix A: Extended connection properties
dataTypeBind Defines data type bind from one type to a different type. (Since:
set_bind Jaybird 3.0.9 Since: Firebird 4) Multiple bind definitions are
separated by semicolons. When used in a JDBC url, the semicolon
must be escaped using %3B. See Data type bind support for more
information.
sessionTimeZone Configures the session time zone. (Since: Jaybird 3.0.6) In Jaybird
3, only configures the Firebird 4 server-side session time zone. In
Jaybird 4, also configures the time zone used for legacy datetime
conversion on all Firebird versions. See Connection property
sessionTimeZone for more information.
Default: not set (Jaybird 3 and earlier), or the JVM default time
zone (Since: Jaybird 4)
136
Appendix A: Extended connection properties
In addition, Jaybird allows using arbitrary Database Parameters Block entries as connection
properties (provided they are defined in Jaybird’s org.firebirdsql.gds.ISCConstants). The current
Firebird API has almost 90 DPB parameters, however only few of them are interesting for regular
users. If a DPB item called isc_dpb_XXX exists, then Jaybird allows these to be specified as
isc_dpb_XXX and XXX. By default properties are mapped as string DPB items. If a DPB item requires
another type, it will need to be explicitly defined in Jaybird.
137
Appendix A: Extended connection properties
For data sources, this feature is exposed using a definition properties file and the setTpbMapping
property. See Transaction Isolation Levels for more information.
138
Appendix B: System properties
B.1. Logging
To configure logging, the following system properties are available. See Logging for details.
org.firebirdsql.jdbc.fallbackConsoleLogger
Since: Jaybird 2.2.8 Removed in: Jaybird 3 Set to true for fallback to log to console if log4j is not
used or not available
FBLog4j
Removed in: Jaybird 3 Set to true to attempt to use log4j (if on classpath) for logging
org.firebirdsql.jdbc.useLog4j
Since: Jaybird 2.2.8 Removed in: Jaybird 3 Alias for FBLog4j
org.firebirdsql.jdbc.forceConsoleLogger
Since: Jaybird 3 Set to true to force logging to console (System.out for info, System.err for warn,
error and fatal) instead of default java.util.logging
org.firebirdsql.jdbc.disableLogging
Since: Jaybird 3 Set to true to disable logging
org.firebirdsql.jdbc.loggerImplementation
Since: Jaybird 3 Fully-qualified name of org.firebirdsql.logging.Logger implementation to use
for logging
org.firebirdsql.jdbc.processName
Since: Jaybird 2.2 Process name to send to Firebird
org.firebirdsql.jdbc.pid
Since: Jaybird 2.2 PID to send to Firebird (must be a valid integer)
The property values are read for each connect, so the value can be changed at any time.
139
Appendix B: System properties
org.firebirdsql.jdbc.defaultConnectionEncoding
Since: Jaybird 3 Firebird character set name to use as connection character set when no explicit
connection character set is configured (defaults to NONE when not set)
org.firebirdsql.jdbc.requireConnectionEncoding
Since: Jaybird 3.0.2 Set to true to disallow connections without an explicit connection character
set. This property will have no effect if org.firebirdsql.jdbc.defaultConnectionEncoding has been
set.
The property values are read for each connect, so the value can be changed at any time.
org.firebirdsql.jna.syncWrapNativeLibrary
Since: Jaybird 3 Set to true to add a synchronization proxy around the native client library.
org.firebirdsql.datatypeCoderCacheSize
Since: Jaybird 4 Integer value for the number of encoding specific data type coders cached
(default and minimum is 1). Setting to a higher value may improve performance, most common
use case is connection character set NONE with a database that uses more than one character set
for its columns. Jaybird will log a warning ("Cleared encoding specific datatype coder cache [..]")
when the cache size was exceeded.
org.firebirdsql.nativeResourceShutdownDisabled
Since: Jaybird 4 Set to true to disable automatic shutdown and unload of native libraries and
other native resources. Normally you should only use this if the automatic shutdown
misbehaves and causes application errors. If you need to set this to true, we’d appreciate it if you
post a message to the Firebird-Java list with details on why you needed to enable this, so we can
improve or fix this feature.
These properties need to be set before Jaybird is loaded and used. Technically,
org.firebirdsql.jna.syncWrapNativeLibrary is dynamic, but a native library will usually be loaded
once.
jdk.net.useFastTcpLoopback
Since: Firebird 3.0.2 Since: Jave 8 update 60 Since: Windows 8 / Windows Server 2012 Set to true
on Windows to enable "TCP Loopback Fast Path" (SIO_LOOPBACK_FAST_PATH socket option). "TCP
140
Appendix B: System properties
141
Appendix B: System properties
142
Appendix C: Data Type Conversion Table
SMA INT BIG REA FLO DOU DEC NUM CHA VAR BLO BLO BLO DAT TIM TIM BOO DEC
LLI EGE INT L AT BLE IMA ERI R CHA B B B E E EST LEA FLO
NT R L C R SUB SUB SUB AMP N AT
_TY _TY _TY
PE PE PE
1 0 < 0
String X X X X X X X X X X X X X X X X X X
BigDecimal X X X X X X X X X X X X
Boolean X X X X X X X X X X X X
143
Appendix C: Data Type Conversion Table
SMA INT BIG REA FLO DOU DEC NUM CHA VAR BLO BLO BLO DAT TIM TIM BOO DEC
LLI EGE INT L AT BLE IMA ERI R CHA B B B E E EST LEA FLO
NT R L C R SUB SUB SUB AMP N AT
_TY _TY _TY
PE PE PE
1 0 < 0
Integer X X X X X X X X X X X X
Long X X X X X X X X X X X X
Float X X X X X X X X X X X X
Double X X X X X X X X X X X X
byte[] X X X
Blob X X X
Date X X
Time X
Timestamp X X
[26] A Firebird REAL is an alias for FLOAT and by default handled as java.sql.Types.FLOAT
[27] JDBC does not yet define a java.sql.Types code for DECFLOAT
144
Appendix D: Connection Pool Properties
The documentation in this section is only valid for Jaybird 2.2 and earlier.
Connection pooling was removed from Jaybird 3.0. Either use the connection pool
provided by your application server, or use a third-party connection pool like c3p0
[https://www.mchange.com/projects/c3p0/], Apache DBCP [https://commons.apache.org/proper/
commons-dbcp/] or HikariCP [https://brettwooldridge.github.io/HikariCP/].
Property Description
maxIdleTime Maximum time in milliseconds after which an idle connection in
the pool is closed.
maxPoolSize Maximum number of open physical connections.
minPoolSize Minimum number of open physical connections. If value is
greater than 0, corresponding number of connections will be
opened when first connection is obtained.
maxStatements Maximum size of the prepared statement pool. If zero, statement
pooling is switched off. When the application requests more
statements than can be kept in the pool, Jaybird will allow
creating those statements, however closing them would not
return them back to the pool, but rather immediately release the
resources.
Property Description
blockingTimeout Maximum time in milliseconds during which application can be
blocked waiting for a connection from the pool. If no free
connection can be obtained, an exception is thrown.
retryInterval Period in which the pool will try to obtain a new connection
while blocking the application.
pooling Allows to switch connection pooling off.
145
Appendix D: Connection Pool Properties
Property Description
statementPooling Allows to switch statement pooling off.
pingStatement Statement that will be used to "ping" the JDBC connection, in
other words, to check if it is still alive. This statement must
always succeed. he default SQL statement for the Firebird
database is "SELECT CAST(1 AS INTEGER) FROM rdb$database".
pingInterval Time during which connection is believed to be valid in any case.
The pool "pings" the connection before giving it to the application
only if more than specified amount of time passed since last
"ping".
isolation Default transaction isolation level. All connections returned from
the pool will have this isolation level. One of:
• TRANSACTION_READ_COMMITTED
• TRANSACTION_REPEATABLE_READ
• TRANSACTION_SERIALIZABLE
Property Description
freeSize Tells how many free connections are in the pool. Value is
between 0 and totalSize.
workingSize Tells how many connections were taken from the pool and are
currently used in the application.
totalSize Total size of open connection. At the pool creation – 0, after
obtaining first connection – between minPoolSize and
maxPoolSize.
Property Description
database Path to the database in the format
[host/port:]/path/to/database.fdb
146
Appendix D: Connection Pool Properties
Property Description
type Type of the driver to use. Possible values are:
blobBufferSize Size of the buffer used to transfer BLOB content. Maximum value
is 64k-1.
socketBufferSize Size of the socket buffer. Needed on some Linux machines to fix
performance degradation.
charSet Character set for the connection. Similar to encoding property, but
accepts Java names instead of Firebird ones.
encoding Character encoding for the connection. See Firebird
documentation for more information.
userName Name of the user that will be used by default.
password Corresponding password.
roleName SQL role to use.
tpbMapping TPB mapping for different transaction isolation modes.
For those Java applications that still need non-standard connectivity parameters, DataSource and
ConnectionPoolDataSource implementations provides a getter and two setters:
• setNonStandardProperty(String name, String value) method sets the property specified by the
first parameter to a value contained in the second parameter.
147
Appendix D: Connection Pool Properties
dataSource.setNonStandardProperty("isc_dpb_sql_dialect=3");
The parameter syntax of the last method is not very common in Java code, it would be much more
natural to use two-parameter setter. However, it has a specialized use, because there’s no
possibility to use two-parameter setter method in configuration files. Usually, when setting a
configuration parameter of a data source, web-containers use the Java reflection API and consider
only those setters that take one parameter. For instance, in the Tomcat server the configuration
parameter would look like this:
<parameter>
<name>nonStandardProperty</name>
<value>sql_dialect=3</value>
</parameter>
<name>[<whitespace>][{=|:|<whitespace>}[<whitespace>]<value>]
where <name> is the name of the DPB parameter, and <value> is its value. The two are separated by
any combination of whitespace and either whitespace or "=" (equal sign) or ":" (colon) characters.
Considering the aliases described in Extended connection properties. For example following values
are equivalent:
isc_dpb_sql_dialect 3
isc_dpb_sql_dialect : 3
sql_dialect : 3
sql_dialect=3
148
Appendix E: Character Encodings
• The database encoding defines the character set in which CHAR, VARCHAR and BLOB SUB_TYPE TEXT
fields are physically stored on the disk. There is a default database encoding that is specified
during database creation. It is also possible to specify character sets on a per column basis.
• The client connection encoding defines a character set in which client will send and expects to
receive character data. This encoding might or might not match the database default encoding.
Firebird performs translation between character sets of the client connection and the character set
of the content. The list of allowed character sets as well as the allowed translations between them
[
are specified in the fbintl shared library located in the intl/ directory of the Firebird installation.
28]
There is also a special character set NONE that tells Firebird not to interpret the contents of the
character field.
• If source and target character sets match, send the content unchanged.
• If there is a direct translation rule between source and target character sets, use that rule.
• If there is no direct translation rule, check if there is rule to translate the source character set
into the UTF8 character set and a rule to translate from UTF8 into the target character set. If yes,
use these two rules for translation.
There are two boundary cases that we will consider here, one when Firebird database was created
[29]
with default character set UTF8, another when the Firebird database was created without
specifying the character set (i.e. character set NONE).
149
Appendix E: Character Encodings
The character set UTF8 in Firebird 2.0 and higher is a Unicode character set that uses UTF-8
encoding and occupies from one to four 8-bit units. Firebird has supported Unicode character set
for a long time, however its implementation was deficient in Firebird 1.5 and earleir – it did not
support proper uppercasing and correct sorting. These issues were addressed in Firebird 2.0 and at
the moment nothing prevents developers from using Unicode in the database and on the client side,
which greatly simplifies the internationalization and localization of the applications.
A developer must ensure two things to enable use of Unicode characters in the database and the
application:
1. The database objects must be defined with the UTF8 character set; this can be done by either
creating database with default UTF8 character set or by adding CHARACTER SET UTF8 clause to the
column or domain definitions.
2. The encoding connection property in the JDBC driver has to be set to UTF8; this can be done in
several ways: the easiest one is to add the appropriate parameter to the JDBC URL (see the first
example), another possibility is to use appropriate method of the DriverManager class (see the
second example). Applications that use DataSource interface to obtain the database connections
[30]
also have access to the encoding property.
props.setProperty("user", "SYSDBA");
props.setProperty("password", "masterkey");
props.setProperty("encoding", "UTF8");
There are a few limitations related to using the UTF8 character set:
• It is not possible to create Unicode columns longer than 8191 Unicode characters; this limitation
is caused by the fact that the longest possible VARCHAR column can occupy 32765 bytes (32767 for
CHAR columns) and a single UTF8 character can occupy up to four bytes.
[31]
• It is not possible to index Unicode columns longer than 1023 characters; this limitation is
caused by the fact that the longest index key cannot be longer than a quarter of the database
page, which in Firebird 2.0 and higher can be maximum 16k and the before mentioned fact that
each UTF8 character can occupy up to four bytes.
150
Appendix E: Character Encodings
It should be mentioned that using Unicode character set might cause noticeable performance
degradation when the database is accessed over wide-area networks. This mainly applies to the
cases when non-latin characters are stored in the database, as those characters will require two or
more bytes, which in turn might cause additional roudtrips to the server to fetch data.
Java introduces additional complexity when the NONE character set is used. The reason for this is
that Java internally stores all strings in Unicode format, and the application must define the
character encoding for the byte contents to the JVM. When the NONE character set is used, Jaybird
does not know how to interpret the received data. The only choice that is left to Jaybird is to
construct a string using the default character set of the JVM, which usually matches the regional
settings of the operating system and can be accessed from within the JVM through the
file.encoding system property.
(Since: Jaybird 3) Starting with Jaybird 3, with connection character set NONE, Jaybird will use the
explicit character set of CHAR, VARCHAR and BLOB SUB_TYPE TEXT columns for the conversion. This
addresses most of the problems described in this paragraph, except for columns without an explicit
character set (ie their character set is NONE).
It is clear that a conversion using default character set that happens inside the JVM can lead to
errors when the same content is accessed from two or more different Java Virtual Machines that
have different configuration. One application running on the computer with, for example, Russian
regional settings saves the Russian text (the default character set of the JVM is Cp1251) and another
application running on computer with German regional settings (default character set is Cp1252)
will read in such case some special or accented characters. However, when all client applications
run same OS with the same regional settings in most cases will not have any severe consequences
(except probably wrong sorting order or uppercasing on the server side).
On Linux and other Unix platforms it might have more severe consequences as it is very common
that regional settings are not configured and that the default "C" locale is used and the non-ASCII
characters will be replaced with question marks ("?").
Therefore, application should use NONE character encoding as an encoding for a database and a
connection only when at least one of the following is met:
• It is guaranteed that all Java Virtual Machines accessing the database will have the same default
encoding that can correctly handle all characters stored in the database,
• (Since: Jaybird 3) All columns have an explicit character set. When columns have an explicit
character set (other than NONE) and connection character set NONE is used, Firebird will send an
identifier of the character set of each column, and Jaybird will use that character set for the
conversion.
As a partial workaround, you can specify the encoding that should be used to interpret bytes
coming from the server in the charSet connection property. The following rules are used when
interpreting the encoding and charSet properties:
• When only encoding property specified, Jaybird uses the default mapping between server and
151
Appendix E: Character Encodings
Java encodings. When encoding property is not set or set to NONE and charSet property is not set,
the default JVM encoding is used to interpret bytes coming from the server.
• When only charSet property is specified, Jaybird uses the reverse mapping to specify the
connection encoding for the server and interprets byte stream according to the value of the
property.
• When both encoding and charSet property are specified, Jaybird sets the connection encoding
according to the value of the encoding property, but interprets the byte stream according to the
charSet property. (Since: Jaybird 3) With Jaybird 3 and higher, this option has limitations when
encoding=NONE: the conversion using charSet will only be applied for columns that don’t have an
explicit character set, otherwise that explicit character set is used for the conversion.
The last case is most powerful, but also is the most dangerous in use. When used properly, it can
solve the problems with the legacy databases; when used incorrectly, one can easily trash the
content of the database.
ASCII ASCII 1 -
152
Appendix E: Character Encodings
WIN1255 Cp1255 1 -
WIN1256 Cp1256 1 -
WIN1257 Cp1257 1 -
153
Appendix E: Character Encodings
154
Appendix F: Supported JDBC Scalar Functions
Not all functions described in the JDBC specification have corresponding built-in functions in
[32]
Firebird, but some are available in the standard UDF library ib_udf shipped with Firebird.
Jaybird provides a connection parameter use_standard_udf to configure the driver to assume that
functions from that UDF are available in the database (Removed in: Jaybird 5). In this case Jaybird
will convert all JDBC function calls into the corresponding calls of the UDF functions.
(Since: Jaybird 3) In recent Firebird versions, the number of built-in functions has been greatly
increased, and Jaybird 3 and higher can now map almost all JDBC escapes to those built-in
functions. Using the use_standard_udf is no longer advisable, especially as UDFs are now deprecated
and will be removed in a future Firebird version. Since: Jaybird 5 UDF mode (use_standard_udf) is
no longer available in Jaybird 5 and higher.
Below you will find the list of JDBC functions and whether they have a corresponding equivalent in
the "built-in" and in the "UDF" modes.
155
Appendix F: Supported JDBC Scalar Functions
156
Appendix F: Supported JDBC Scalar Functions
157
Appendix F: Supported JDBC Scalar Functions
158
Appendix F: Supported JDBC Scalar Functions
159
Appendix F: Supported JDBC Scalar Functions
160
Appendix F: Supported JDBC Scalar Functions
• BIGINT
• CHAR
• DATE
• DECIMAL
• DOUBLE PRECISION
• FLOAT
• INTEGER
• REAL
• SMALLINT
• TIME
• TIMESTAMP
• VARCHAR
161
Appendix F: Supported JDBC Scalar Functions
(Since: Jaybird 4) The following improvements where added to CONVERT support in Jaybird 4:
• Contrary to the JDBC specification, we allow explicit length or precision and scale parameters
• (SQL_)VARCHAR, (SQL_)NVARCHAR (and value not a parameter (?)) without explicit length is
converted using TRIM(TRAILING FROM value), which means the result is VARCHAR except for blobs
where this will result in a blob; national character set will be lost. If value is a parameter (?),
and no length is specified, then a length of 50 will be applied (cast to (N)VARCHAR(50)).
• (SQL_)BINARY, and (SQL_)VARBINARY without explicit length will be cast to (VAR)CHAR(50) CHARACTER
SET OCTETS. With explicit length, CHARACTER SET OCTETS is appended.
• (SQL_)DECIMAL and (SQL_)NUMERIC without precision and scale are passed as is, in current
Firebird versions, this means the value will be equivalent to DECIMAL(9,0) (which is equivalent
to INTEGER)
• Unsupported/unknown SQLtype values (or invalid length or precision and scale) are passed as is
to cast, resulting in an error from the Firebird engine if the resulting cast is invalid
[32] On Windows platform it is represented by the ib_udf.dll, on Linux it is represented by the libib_udf.so.
[33] Maps to UDF RAND() taking no parameters. The random number generator is seeded by the current time. There is no function
where the seed can be specified.
[34] Second parameter is ignored in Jaybird 3 and earlier, supported in Jaybird 4 and higher
[35] Second parameter ignored in Jaybird 3 and earlier, supported in Jaybird 4 and higher
[36] In Jaybird 3, the second parameter is ignored, in Jaybird 4 the CHARACTERS parameter only determines that characters are
counted, the ignored blanks (space (0x20) or NUL (0x00)) are not determined by the parameter but by the underlying type
[37] The trailing blanks are also counted, only works if second parameter is omitted
[38] The OCTETS parameter only determines that bytes are counted, the ignored blanks (space (0x20) or NUL (0x00)) are not
determined by the parameter but by the underlying type
[39] In Jaybird 3, start is required, start is optional since Jaybird 4
[40] In Jaybird 3 and earlier only supported without the CHARACTERS parameter
[41] Parameter OCTETS is ignored
[42] Always returns English full names (eg Sunday)
[43] Always returns English full names (eg January)
[44] Either the full path of the database or the alias. See documentation of RDB$GET_CONTEXT('SYSTEM', 'DB_NAME') for details.
162
Appendix G: Jaybird versions
G.1. Jaybird 4
G.1.1. Java support
Jaybird 4 supports Java 7 (JDBC 4.1), Java 8 (JDBC 4.2), and Java 9 and higher (JDBC 4.3).
Given the limited support period for Java 9 and higher versions, we will limit support on those
versions to the most recent LTS version and the latest release. Currently that means we support
Java 11 and Java 13.
Jaybird 4 provides libraries for Java 7, Java 8 and Java 11. The Java 8 builds have the same source
and all JDBC 4.3 related functionality and can be used on Java 9 and higher as well.
Jaybird 4 is not modularized, but all versions declare the automatic module name
org.firebirdsql.jaybird.
Formal support for Firebird 2.0 and 2.1 has been dropped (although in general we expect the driver
to work). The Type 2 and embedded server JDBC drivers use JNA to access the Firebird client or
embedded library.
At the time of release of Jaybird 4, Firebird 4 was still in testing. As a result, support for Firebird 4 is
tentative. There can be incompatibilities with features or changes after Firebird version 4.0.0.1803.
Once Firebird 4 is released, incompatibilities or otherwise breaking changes will be addressed in a
point release of Jaybird 4.
Jaybird 4 supports the protocol improvements of Firebird 4 for statement timeouts, but does not
implement the new batch protocol.
Jaybird time zone support uses functionality added after Firebird 4 beta 1 (4.0.0.1436), you will
need version 4.0.0.1683 or later for the dataTypeBind connection property.
Jaybird 4 supports the extended numeric precision types introduced after Firebird 4 beta 1
(4.0.0.1436), you will need version 4.0.0.1604 to be able to use NUMERIC or DECIMAL with a precision
higher than 18.
163
Appendix G: Jaybird versions
Jaybird does not support the ChaCha wire encryption plugin. This may be added in a future major
or point release.
Specification Details
JDBC 4.3 Jaybird supports most of JDBC 4.3, inasfar the features are required or
supported by Firebird. It is not officially JDBC compliant, because we
currently don’t have access to the TCK.
G.1.4. Distribution
The Jaybird driver has compile-time and run-time dependencies to JCA 1.5. Additionally, if the antlr-
runtime classes are found in the class path, it is possible to use generated key retrieval.
Distribution package
Maven
Alternatively, you can use maven to automatically download Jaybird and its dependencies.
164
Appendix G: Jaybird versions
Groupid: org.firebirdsql.jdbc,
Artifactid: jaybird,
Version: 4.0.0.<java> (where <java> is either java7, java8 or java11)
For example:
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird</artifactId>
<version>4.0.0.java8</version>
</dependency>
If your application is deployed to a Java EE application server, you will need to exclude the
javax.resource:connector-api dependency, and add it as a provided dependency:
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird</artifactId>
<version>4.0.0.java8</version>
<exclusions>
<exclusion>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
<version>1.5</version>
<scope>provided</scope>
</dependency>
If you want to use Type 2 support (native, local or embedded), you need to explicitly include JNA as
a dependency:
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.5.0</version>
</dependency>
For native and local you can use the org.firebirdsql.jdbc:fbclient dependency to provide the
165
Appendix G: Jaybird versions
client library. See Maven dependency for native client for details.
G.2. Jaybird 3
G.2.1. Java support
Jaybird 3 supports Java 7 (JDBC 4.1), Java 8 (JDBC 4.2), and Java 9 - 11 (JDBC 4.3).
There are no Java 9+ specific builds, the Java 8 builds have the same source and all JDBC 4.3 related
functionality.
Given the limited support period for Java 9 and higher versions, we may limit support on those
versions to the most recent LTS version and the latest release.
Jaybird 3.0 is not modularized, but since Jaybird 3.0.3, it declares the automatic module name
org.firebirdsql.jaybird.
Jaybird 3 supports Firebird 2.0 and higher, but is only tested with Firebird 2.5, 3.0 and 4.0.
Formal support for Firebird 1.x has been dropped (although in general we expect the driver to
work). The Type 2 and embedded server JDBC drivers use JNA to access the Firebird client or
embedded library.
Jaybird 3.0.4 added support for wire protocol encryption and database encryption.
Jaybird 3.0 can connect and query Firebird 4. Longer object names are supported.
The new data types introduced in Firebird 4 are not supported. Support for data types like DECFLOAT
and NUMERIC/DECIMAL with precision higher than 18 will be introduced in Jaybird 4.
The Srp256 authentication plugin is supported (Since: Jaybird 3.0.5), but the other SrpNNN plugins
are not.
166
Appendix G: Jaybird versions
Specification Details
JDBC 4.3 Jaybird supports most of JDBC 4.3, inasfar the features are required or
supported by Firebird. It is not officially JDBC compliant, because we
currently don’t have access to the TCK.
G.2.4. Distribution
The Jaybird driver has compile-time and run-time dependencies to JCA 1.5. Additionally, if the antlr-
runtime classes are found in the class path, it is possible to use generated key retrieval.
Distribution package
Maven
Alternatively, you can use maven to automatically download Jaybird and its dependencies.
Groupid: org.firebirdsql.jdbc,
Artifactid: jaybird-jdkXX (where XX is 17 or 18).
Version: 3.0.9
For example:
167
Appendix G: Jaybird versions
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird-jdk18</artifactId>
<version>3.0.9</version>
</dependency>
If your application is deployed to a Java EE application server, you will need to exclude the
javax.resource:connector-api dependency, and add it as a provided dependency:
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird-jdk18</artifactId>
<version>3.0.9</version>
<exclusions>
<exclusion>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
<version>1.5</version>
<scope>provided</scope>
</dependency>
If you want to use Type 2 support (native, local or embedded), you need to explicitly include JNA as
a dependency:
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.4.0</version>
</dependency>
For native and local you can use the org.firebirdsql.jdbc:fbclient dependency to provide the
client library. See Maven dependency for native client for details.
168
Appendix G: Jaybird versions
Jaybird 2.2 supports Java 6 (JDBC 4.0), Java 7 (JDBC 4.1) and Java 8 (JDBC 4.2). Java 5 support was
dropped in Jaybird 2.2.8.
For compatibility with Java 9 modules, version 2.2.14 introduced the automatic module name
org.firebirdsql.jaybird. This guarantees a stable module name for Jaybird, and allows for future
modularization of Jaybird.
Jaybird 2.2 supports Firebird 1.0 and higher, but is only tested with Firebird 2.5 and 3.0.
Connecting to Firebird 3 requires some additional configuration, see Jaybird and Firebird 3.0
[https://github.com/FirebirdSQL/jaybird/wiki/Jaybird-and-Firebird-3] for details.
Firebird 4 is not formally supported in Jaybird 2.2.x, although connecting and most functionality
will work. We suggest that you use Jaybird 3.x or higher for Firebird 4. Support for newer data
types like DECFLOAT and NUMERIC/DECIMAL with precision higher than 18 will be introduced in Jaybird
4.
The Type 2 and embedded server JDBC drivers require the appropriate JNI library. Precompiled JNI
binaries for Windows and Linux platforms are shipped in the default installation, other platforms
require porting/building the JNI library for that platform.
Specification Details
JDBC 4.2 Driver does not fully support JDBC 4.2 features, but implements large
update count methods by calling the normal update count methods, and
methods with SQLType by calling methods accepting the java.sql.Types
integer value. Supports new java.time classes with some caveats.
JDBC 4.1 Driver implements all JDBC 4.1 methods added to existing interfaces. The
driver explicitly supports closeOnCompletion, most other methods
introduced with JDBC 4.1 throw SQLFeatureNotSupportedException.
JDBC 4.0 Driver implements all JDBC 4.0 interfaces and supports exception
chaining.
169
Appendix G: Jaybird versions
G.3.4. Distribution
The Jaybird driver has compile-time and run-time dependencies to JCA 1.5. Additionally, if the antlr-
runtime classes are found in the class path, it is possible to use generated key retrieval.
Distribution package
Jaybird 2.2 has compile-time and run-time dependencies on the JCA 1.5 classes. Additionally, if
Log4J classes are found in the class path, it is possible to enable extensive logging inside the driver.
If the ANTLR runtime classes are absent, the generated keys functionality will not be available.
The Windows DLLs have been built with Microsoft Visual Studio 2010 SP1. To use the native or
embedded driver, you will need to install the Microsoft Visual C++ 2010 SP 1 redistributable
available at:
x86: http://www.microsoft.com/download/en/details.aspx?id=8328
x64: http://www.microsoft.com/download/en/details.aspx?id=13523
Maven
Alternatively, you can use maven to automatically download Jaybird and its dependencies.
Groupid: org.firebirdsql.jdbc,
170
Appendix G: Jaybird versions
For example:
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird-jdk18</artifactId>
<version>2.2.15</version>
</dependency>
If your application is deployed to a Java EE application server, you will need to exclude the
javax.resource:connector-api dependency, and add it as a provided dependency:
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird-jdk18</artifactId>
<version>2.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
<version>1.5</version>
<scope>provided</scope>
</dependency>
171
Appendix G: Jaybird versions
172
Appendix H: License
Appendix H: License
The contents of this Documentation are subject to the Public Documentation License Version 1.0
(the "License"); you may only use this Documentation if you comply with the terms of this License.
A copy of the License is available at http://www.firebirdsql.org/manual/licenses-pdl-text.html.
The Original Documentation is Jaybird 2.1 JDBC driver Java Programmer’s Manual. The Initial
Writer of the Original Documentation is Roman Rokytskyy Copyright © 2004-2008. All Rights
Reserved. (Initial Writer contact(s): [email protected] [mailto:[email protected]]).
Portions created by Mark Rotteveel are Copyright © 2014-2019. All Rights Reserved. (Contributor
contact(s): [email protected] [mailto:[email protected]]).
Portions created by ….. are Copyright ©…..[Insert year(s)]. All Rights Reserved. (Contributor
contact(s):……………[Insert hyperlink/alias]).
173