diff --git a/src/docs/asciidoc/appendices/characterencoding/characterencoding.adoc b/src/docs/asciidoc/appendices/characterencoding/characterencoding.adoc index dcc3e24..2391d6d 100644 --- a/src/docs/asciidoc/appendices/characterencoding/characterencoding.adoc +++ b/src/docs/asciidoc/appendices/characterencoding/characterencoding.adoc @@ -46,7 +46,7 @@ These issues were addressed in Firebird 2.0 and at the moment nothing prevents d A developer must ensure two things to enable use of Unicode characters in the database and the application: . 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. +this can be done by either creating the database with a default character set of `UTF8`, or by adding the `CHARACTER SET UTF8` clause to column or domain definitions. . 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 also have access to the @@ -77,10 +77,10 @@ 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. -* It is not possible to index Unicode columns longer than 1023 characters -- or 2047 characters in Firebird 4.0 with a page size of 32 kilobytes; -this limitation is caused by the fact that the longest index key cannot be longer than a quarter of the database page, which has a maximum of 16k ([.since]_Firebird 4.0_ 32k) and the before mentioned fact that each `UTF8` character can occupy up to four bytes. +* It is not possible to index Unicode columns longer than 2047 characters -- this requires a page size of 32 kilobytes; +this limitation is caused by the fact that the longest index key cannot be longer than a quarter of the database page, which has a maximum of 32k and the fact that each `UTF8` character can occupy up to four bytes. -It should be mentioned that using Unicode character set might cause noticeable performance degradation when the database is accessed over wide-area networks. +Using the `UTF8` 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 roundtrips to the server to fetch data. ==== The NONE character set @@ -91,7 +91,7 @@ When the `NONE` character set is used, Jaybird does not know how to interpret th 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. With connection character set `NONE`, Jaybird uses 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 (i.e. their character set is `NONE`). +This addresses most of the problems described in this section, except for columns without an explicit character set (i.e. 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. @@ -99,9 +99,9 @@ However, when all client applications run on the same OS with the same regional 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: +Therefore, an application should only use `NONE` character encoding as an encoding for a database and a connection when at least one of the following is met: -* Database will contain only ASCII characters, +* The database will contain only ASCII characters, * 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, * 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. diff --git a/src/docs/asciidoc/appendices/jdbcescape/jdbcescape.adoc b/src/docs/asciidoc/appendices/jdbcescape/jdbcescape.adoc index 6f83f19..8d66c6e 100644 --- a/src/docs/asciidoc/appendices/jdbcescape/jdbcescape.adoc +++ b/src/docs/asciidoc/appendices/jdbcescape/jdbcescape.adoc @@ -333,7 +333,7 @@ Legend: X -- available in this mode. |The current local time as a time value |DAYNAME(date) -|Xfootnote:[Always returns English full names (e.g. Sunday)] +|Xfootnote:[Always returns English full names (e.g. "`Sunday`")] |{nbsp} |A character string representing the day component of `date`; the name for the day is specific to the data source @@ -510,5 +510,6 @@ With explicit length, `CHARACTER SET OCTETS` is appended. * `(SQL_)LONGVARBINARY`, `(SQL_)BLOB` will be cast to `BLOB SUB_TYPE BINARY` * `(SQL_)TINYINT` is mapped to `SMALLINT` * `(SQL_)ROWID` is not supported as length of `DB_KEY` values depend on the context -* `(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`) +* `(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)`/`NUMERIC(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 diff --git a/src/docs/asciidoc/appendices/systemproperties/systemproperties.adoc b/src/docs/asciidoc/appendices/systemproperties/systemproperties.adoc index 1deb153..302db24 100644 --- a/src/docs/asciidoc/appendices/systemproperties/systemproperties.adoc +++ b/src/docs/asciidoc/appendices/systemproperties/systemproperties.adoc @@ -123,6 +123,8 @@ The following system properties control other global behaviour of Jaybird. `org.firebirdsql.jna.syncWrapNativeLibrary`:: Set to true to add a synchronization proxy around the native client library. ++ +This can be used to address thread-safety issues with older client libraries (Firebird 2.1 and older, as far as we know). `org.firebirdsql.datatypeCoderCacheSize`:: 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. diff --git a/src/docs/asciidoc/chapters/connection/connection.adoc b/src/docs/asciidoc/chapters/connection/connection.adoc index 3fec55c..85af870 100644 --- a/src/docs/asciidoc/chapters/connection/connection.adoc +++ b/src/docs/asciidoc/chapters/connection/connection.adoc @@ -6,7 +6,8 @@ Jaybird is a regular JDBC driver and supports two primary ways to obtain connect [[connection-drivermanager]] === Obtaining connection java.sql.DriverManager -`java.sql.DriverManager` was the first connection factory in Java. It is based on the concept of the JDBC URL, a string that uniquely identifies the database to connect. +`java.sql.DriverManager` is a database connection factory introduced with JDBC 1. +It is based on the concept of the JDBC URL, a string that uniquely identifies the database to connect. The driver manager then checks which driver(s) -- if any -- can establish a connection. There is also support to specify additional connection parameters, like username and password. @@ -19,14 +20,14 @@ jdbc:firebird://localhost:3050/c:/database/example.fdb * `jdbc` + JDBC protocol -* `firebird` or `firebirdsql` + +* `firebird` (also supported: `firebirdsql`) + JDBC subprotocol, identifies driver to use, in this case Jaybird * `//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 `//:/` The first part, `jdbc:firebird:` or `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. +In other words, it specifies the type of connection that the application wants to obtain, in this example, a connection to a Firebird database. An example of obtaining a connection is shown below. @@ -40,14 +41,13 @@ import java.sql.*; public class HelloServer { public static void main(String[] args) throws Exception { - Class.forName("org.firebirdsql.jdbc.FBDriver"); // <1> - Connection connection = DriverManager.getConnection( - "jdbc:firebird://localhost:3050/c:/db/employee.fdb", - "SYSDBA", "masterkey"); // <2> - - // do something here + try (Connection connection = DriverManager.getConnection( + "jdbc:firebird://localhost:3050/c:/db/employee.fdb", + "SYSDBA", "masterkey")) { // <2> + // use connection here + } } } ---- @@ -56,7 +56,7 @@ The first line of this code is important -- it tells Java to load the Jaybird JD As required by the JDBC specification, at this point driver registers itself with `java.sql.DriverManager`. Since Java 6 (JDBC 4), explicitly loading the driver using `Class.forName("org.firebirdsql.jdbc.FBDriver")` is no longer necessary, except when the driver is not on the system class path. -Examples where it may be necessary to explicitly load the driver are web applications that include the driver in the deployment. +Examples where it may be necessary to explicitly load the driver are web applications that include the driver in the deployment (e.g. in `WEB-INF/lib` of the WAR). There, the driver is not on the system class path, so it will need to be loaded explicitly. We will leave out usages of `Class.forName` in further examples, they will work because of automatic driver loading. @@ -78,8 +78,8 @@ The JDBC specification requires that during class initialization the driver regi .... 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 (`:`). +3. The JDBC driver class 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: + @@ -129,8 +129,7 @@ import java.util.*; public class HelloServerWithEncoding { public static void main(String[] args) throws Exception { - Properties props = new Properties(); - + var props = new Properties(); props.setProperty("user", "SYSDBA"); props.setProperty("password", "masterkey"); props.setProperty("encoding", "UTF8"); @@ -138,9 +137,7 @@ public class HelloServerWithEncoding { try (Connection connection = DriverManager.getConnection( "jdbc:firebird://localhost:3050/C:/db/employee.fdb", props)) { - - // do something here - + // use connection here } } } @@ -149,10 +146,10 @@ public class HelloServerWithEncoding { 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 <>. +The list of properties available in Jaybird can be found in <>. -It is not always possible to use the above described method. -Jaybird also provides a possibility to specify extended properties in the JDBC URL. +It is not always possible to use the above described method to add properties. +Jaybird also provides a possibility to specify connection properties in the JDBC URL. .Extended JDBC URL format .... @@ -163,10 +160,8 @@ jdbc:firebird://host[:port]/? 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. - -NOTE: Jaybird only supports URL encoding in Jaybird 4 and higher. +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 '```;```'. +The following example is equivalent to the previous example. [source,java] .Specifying extended properties in the JDBC URL @@ -184,20 +179,24 @@ Connection connection = DriverManager.getConnection( [[connection-drivermanager-props-urlencoding]] ===== URL encoding in query part of JDBC URL +NOTE: Jaybird only supports URL encoding in Jaybird 4 and higher. + UTF-8 URL encoded values (and keys) can be used 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: +This can be used to include otherwise unsupported characters in a connection property value: * `;` escaped as `%3B` * `&` escaped as `%26` +* `{plus}` escaped as `%2B` ++ +A {plus} in the query part means _space_ (0x20), so occurrences of `{plus}` (_plus_) need to be escaped; +make sure to do this for _base64_ encoded values of `dbCryptConfig`, or better yet use the _base64url_ encoding instead. +* `%` escaped as `%25`. ++ +A `%` in the query part introduces an escape, so occurrences of `%` (_percent_) need to be escaped. +* Optionally, a _space_ (0x20) can be escaped as {plus} -In addition, the following characters must also be escaped: - -* `{plus}` in the query part now means _space_ (0x20), so occurrences of `{plus}` (_plus_) need to be escaped as `%2B`; -make sure to do this for _base64_ encoded values of `dbCryptConfig` (or use the _base64url_ encoding instead) -* `%` 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. +URL encoding can also be used to encode any Unicode codepoint in the query string. Jaybird will always use UTF-8 for decoding. Invalid URL encoded values will throw a `SQLNonTransientConnectionException`. @@ -213,6 +212,15 @@ Data sources can be created and configured using code or bean introspection, loo Jaybird itself provides one `javax.sql.DataSource` implementation, `org.firebirdsql.ds.FBSimpleDataSource`, which is a plain factory of connections, without connection pooling. +[TIP] +==== +If you need connection pooling, use a third-party connection pool library like https://brettwooldridge.github.io/HikariCP/[HikariCP^], https://commons.apache.org/proper/commons-dbcp/[DBCP^], or https://www.mchange.com/projects/c3p0/[c3p0^]. +Application servers, and for example Tomcat, also provide built-in connection pool support. +Consult their documentation for more information. + +See also <>. +==== + A simple example of creating a data source and obtaining a connection via a `DataSource` object is shown below. [source,java] @@ -237,7 +245,7 @@ public class HelloServerDataSource { ds.setDatabaseName("C:/database/employee.fdb"); try (Connection connection = ds.getConnection()) { - // do something here... + // use connection here } } } @@ -302,6 +310,8 @@ The `DataSource` implementation supports all connection properties available to ==== Manually binding to JNDI like shown above is uncommon. If you find yourself copying this code, rethink what you're doing. + +In fact, use of JNDI is extremely uncommon these days. ==== [[driver-types]] @@ -320,6 +330,7 @@ The `PURE_JAVA` type (JDBC Type 4) uses a pure Java implementation of the Firebi 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. +Some Jaybird features are only available in the pure Java implementation. To obtain a connection using the `PURE_JAVA` driver type you have to use a JDBC URL as shown in <>. @@ -343,9 +354,7 @@ If _portNumber_ is not specified, it defaults to `3050`. In theory, even `` and _databaseName_ are optional, but this requires specifying the database name using connection property `databaseName`, which is possible, but not recommended. -When using `javax.sql.DataSource` implementation, you can specify either `"PURE_JAVA"` or `"TYPE4"` driver type, however this type is used by default. - -Some URL examples +When using `javax.sql.DataSource` implementation, you can specify either `"PURE_JAVA"` or `"TYPE4"` driver type, however this type is already used by default. .Pure Java URL examples [listing] @@ -403,7 +412,7 @@ The following JDBC URL syntax is supported: ---- [.since]_Jaybird 5_ Since Jaybird 5, all URLs supported by fbclient can be used. -The supported URLs depend on the fbclient version and the OS (e.g. XNET and WNET are Windows only, and WNET support will be removed in Firebird 5). +The supported URLs depend on the fbclient version and the OS (e.g. XNET and WNET are Windows only, and WNET support has been removed in Firebird 5). When connecting to a local database server using the `LOCAL` driver, you should use following: @@ -545,11 +554,11 @@ The following JDBC URL syntax is supported: [listing,subs=+quotes] ---- ::= - jdbc:firebird[sql]:embedded:_dbname-or-alias_ + jdbc:firebird[sql]:embedded:__dbname-or-alias__ ---- In practice, the URL accepts the same `` values as described for `NATIVE`. -That is, the embedded server acts as client library (i.e. you get the same Type 2 behavior as you would get with using "native"). +That is, the embedded server also acts as client library (i.e. you get the same Type 2 behavior as you would get with using "native"). This driver tries to load `fbembed.dll/libfbembed.so` (the name used in Firebird 2.5 and earlier) and `fbclient.dll/libfbclient.so`. @@ -570,7 +579,7 @@ This implies the same restrictions on the classloader that will load the Jaybird By default, the Firebird embedded library opens databases in exclusive mode. This means that this particular database is accessible only to one Java virtual machine. -This can be changed by the `ServerMode` setting in `firebird.conf`. +This can be changed with the `ServerMode` setting in `firebird.conf`. [[driver-ooremote]] ==== OOREMOTE type @@ -608,7 +617,7 @@ Each time a connection is opened via `DriverManager`, a new physical connection It is closed when the connection is closed. To avoid the overhead of creating connections, you can use a connection pool implementation to maintain a cache of open physical connections that can be reused between user sessions. -Since Jaybird 3, Jaybird no longer provides a connection pool. +Since Jaybird 3, Jaybird no longer provides its own connection pool implementation. If you need a `javax.sql.DataSource` implementation that provides a connection pool, either use the connection pool support of your application server, or consider using https://brettwooldridge.github.io/HikariCP/[HikariCP^], https://commons.apache.org/proper/commons-dbcp/[DBCP^], or https://www.mchange.com/projects/c3p0/[c3p0^]. [[connection-pooling-hikaricp]] diff --git a/src/docs/asciidoc/chapters/exceptionhandling/exceptionhandling.adoc b/src/docs/asciidoc/chapters/exceptionhandling/exceptionhandling.adoc index b6b764c..f3db514 100644 --- a/src/docs/asciidoc/chapters/exceptionhandling/exceptionhandling.adoc +++ b/src/docs/asciidoc/chapters/exceptionhandling/exceptionhandling.adoc @@ -6,20 +6,13 @@ directly affects the stability of the application. Correct handling of the error cases guarantees correct functioning of the client code as well as the database server. -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. +All methods of the interfaces defined in the JDBC specification throw instances of `java.sql.SQLException` -- or a subclass -- to notify about error conditions that happen during request processing. +`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. === Working with exceptions -Exception handling becomes even more important if we consider that -this topic is either ignored or presented in incorrect form in most -JDBC tutorials. The https://docs.oracle.com/javase/tutorial/jdbc/index.html[official JDBC tutorial from Oracle] -briefly mentions that exceptions should be handled by using try/catch blocks -only at the end of the course, but neither reasons for doing this nor the -best practices are presented. +Exception handling becomes even more important if we consider that this topic is either ignored or presented in incorrect form in most JDBC tutorials. +The https://docs.oracle.com/javase/tutorial/jdbc/index.html[official JDBC tutorial from Oracle^] briefly mentions that exceptions should be handled by using try/catch blocks only at the end of the course, but neither reasons for doing this nor the best practices are presented. There are good reasons to think about exception handling in your applications before you start coding. First of all, it is very hard to @@ -34,7 +27,7 @@ By checking the error code which is sent with the exception, an application can And last but not least, there is resource management. When an exception happens in a 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, 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. +All these objects not only take memory in the Java Virtual Machine of the application, but also consume memory and possibly hold locks 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: diff --git a/src/docs/asciidoc/chapters/introduction/introduction.adoc b/src/docs/asciidoc/chapters/introduction/introduction.adoc index 7c5ed8c..1806911 100644 --- a/src/docs/asciidoc/chapters/introduction/introduction.adoc +++ b/src/docs/asciidoc/chapters/introduction/introduction.adoc @@ -49,11 +49,9 @@ The JCA layer is an implementation of the Java Connector Architecture specificat * [.since]_Jaybird 5_ The XCA layer is a replacement of the JCA layer of previous versions. * The JDBC layer is an implementation of the JDBC specification. -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. +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 classes provide features for database backup/restore, user management, statistics gathering, etc. [[distribution]] === Jaybird Distribution @@ -107,20 +105,24 @@ The Jaybird team uses JUnit test cases to assure the quality of the released dri During development unit tests are extensively used. Committing a code change to the source control is not allowed until it passes all existing unit tests. Each reproducible bug usually gets its own test case. -This guarantees that a clean check out can be compiled and will not contain any previously discovered and fixed bugs. -Currently there are more than 9000 test cases covering most of the driver code. +This guarantees that a clean check out can be compiled and will not contain any previously discovered and fixed bugs. + +Currently, there are more than 9000 test cases covering most of the driver code. +A subset of the tests are automatically run -- through a GitHub Action -- for each push to the repository. === Useful resources ==== JDBC -For JDBC documentation, see https://www.oracle.com/java/technologies/javase/javase-tech-database.html[^]. +For JDBC documentation, see https://www.oracle.com/java/technologies/javase/javase-tech-database.html[Java SE Technologies - Database^]. + +For the JDBC specification, see https://jcp.org/en/jsr/detail?id=221[JSR 221: JDBC^TM^ 4.0 API Specification^] (covers JDBC 4.0 - 4.3). ==== Firebird -General information about the Firebird database is available from the Firebird website (https://www.firebirdsql.org/[^]). +General information about the Firebird database is available from the Firebird website (https://firebirdsql.org/[^]). -For information about using SQL in Firebird, see the https://www.firebirdsql.org/file/documentation/html/en/refdocs/fblangref40/firebird-40-language-reference.html[Firebird 4.0 Language Reference^] and other documents available from the https://www.firebirdsql.org/en/reference-manuals/[Reference Manuals^] section of the Firebird website. +For information about using SQL in Firebird, see the https://firebirdsql.org/file/documentation/html/en/refdocs/fblangref50/firebird-50-language-reference.html[Firebird 5.0 Language Reference^] and other documents available from the https://firebirdsql.org/en/reference-manuals/[Reference Manuals^] section of the Firebird website. ==== Jaybird Support @@ -130,7 +132,7 @@ Support for Jaybird is available through the following channels: + You can subscribe to the mailing list by sending an email to firebird-java+subscribe@googlegroups.com (this does not require a Google account). Alternatively, you can join the group at https://groups.google.com/g/firebird-java[firebird-java Google Group^] (this requires a Google account). -* On https://www.firebirdsql.org/file/documentation/drivers_documentation/java/faq.html[Jaybird Frequently Asked Questions^]. +* On https://firebirdsql.org/docs/drivers/java/faq.html[Jaybird Frequently Asked Questions^]. * On https://github.com/FirebirdSQL/jaybird/wiki/[Jaybird wiki^]. * On https://stackoverflow.com/[Stack Overflow^], please tag your questions with *jaybird* and *firebird* @@ -142,11 +144,11 @@ see https://stackoverflow.com/tour[Stack Overflow Tour^] and https://stackoverfl There are several ways you can contribute to Jaybird or Firebird in general: -* Participate on the mailing lists (see https://www.firebirdsql.org/en/mailing-lists/[^]) +* Participate on the mailing lists (see https://firebirdsql.org/en/mailing-lists/[^]) * Report bugs or submit patches on the tracker (see <>) * Create pull requests on GitHub (https://github.com/FirebirdSQL/jaybird[^]) * Become a developer (for Jaybird contact us on https://groups.google.com/g/firebird-java[firebird-java^], for Firebird in general, use the https://groups.google.com/g/firebird-devel[firebird-devel Google Group^]) -* Become a paying member or sponsor of the Firebird Foundation (see https://www.firebirdsql.org/en/firebird-foundation/[^]) +* Become a paying member or sponsor of the Firebird Foundation (see https://firebirdsql.org/en/firebird-foundation/[^]) [[intro-reporting-bugs]] ==== Reporting Bugs @@ -157,8 +159,8 @@ List members may be able to help out to determine if it is an actual bug, provid You can report bugs in the https://github.com/FirebirdSQL/jaybird/issues[Jaybird bug tracker^] on GitHub. -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. +When reporting bugs, please provide a minimal, but complete reproduction, including databases and source code to reproduce the problem. +Patches or pull requests to fix bugs are also appreciated. +Make sure the patch is against a recent master version of the code. +You can also fork the https://github.com/FirebirdSQL/jaybird[jaybird repository^] and create pull requests. diff --git a/src/docs/asciidoc/chapters/resultsets/resultsets.adoc b/src/docs/asciidoc/chapters/resultsets/resultsets.adoc index d6a5dc9..9698ef9 100644 --- a/src/docs/asciidoc/chapters/resultsets/resultsets.adoc +++ b/src/docs/asciidoc/chapters/resultsets/resultsets.adoc @@ -1,7 +1,7 @@ [[resultsets]] == Working with result sets -When a SELECT statement is executed, the results of the query are returned through the implementation of the `java.sql.ResultSet` interface. +When a `SELECT` statement is executed, the results of the query are returned through the implementation of the `java.sql.ResultSet` interface. === ResultSet properties @@ -10,7 +10,7 @@ When a SELECT statement is executed, the results of the query are returned throu The JDBC specification defines three types of result sets -* `TYPE_FORWARD_ONLY` -- the result set is not scrollable, cursor can only move forward. +* `TYPE_FORWARD_ONLY` -- the result set is not scrollable, the 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, the 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. @@ -35,7 +35,8 @@ A future version may enable this behaviour by default. 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: +The result set concurrency is specified during statement creation and cannot be changed later. +JDBC defines two types of result set concurrency, which are both supported by Jaybird: * `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. diff --git a/src/docs/asciidoc/chapters/services/services.adoc b/src/docs/asciidoc/chapters/services/services.adoc index 562a93b..3ad1014 100644 --- a/src/docs/asciidoc/chapters/services/services.adoc +++ b/src/docs/asciidoc/chapters/services/services.adoc @@ -701,12 +701,9 @@ NFS shares.], 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.) -* 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. +* in `AUTO` mode, the database continues operating even if the shadow becomes unavailable (disk or file system failure, remote node is not accessible, etc.) +* in `MANUAL` mode all database operations are halted until the problem is fixed. +Usually this means that the DBA has to kill the unavailable shadow and define a new one. The `MaintenanceManager` provides a `killUnavailableShadows()` method to kill the unavailable shadows. This is equivalent to the `gfix -kill` @@ -722,18 +719,18 @@ which the management class is connected. ==== Database validation and repair -The Firebird server does its best to keep the database file in a consistent form. -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. +The Firebird server does its best to keep the database file in a consistent state. +This is achieved by an 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. a crash of the file system or hardware failure, the database file becomes corrupted. Firebird server can detect such cases including * Orphan pages. These are 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; +Such pages have to be marked as unused, so the server can use them again; * Corrupted pages. These are database pages that were corrupted/damaged by 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. +The `MaintenanceManager` class provides a `validateDatabase()` method to perform a simple health check of the database, releasing 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. @@ -768,20 +765,21 @@ After this operation database can be backed up and restored to a different place [CAUTION] ==== The presence of checksum errors and subsequent use of `markCorruptedRecords()` method will mark all corrupted data as unused space. -You have to perform a careful check after backup/restore cycle to assess the damage. +You have to perform a careful check after a backup and restore cycle to assess the damage. ==== ==== Limbo transactions -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 Javafootnote:[ +Limbo transactions -- or in-limbo transactions -- are transactions that were prepared for commit but were never committed or rolled back; +or in other words, an incomplete two-phase commit. +This can happen, for example, with a database used by JTA-enabled applications from Javafootnote:[ Another reason for limbo transactions are multi-database transactions which can be initiated via the native Firebird API. However, since Jaybird does not provide methods to initiate them, we do not consider them in this manual.]. -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 prevent garbage collection, since the garbage collector does not know whether it can discard the record versions of the in-limbo transaction. +A limbo transactions affects the normal database operation, since the records that were modified in that transactions are not available, as Firebird does not know whether the new version will be committed or rolled back and blocks access to them. +Also, limbo transactions prevent garbage collection, since the garbage collector does not know whether it can discard the record versions of the 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: +Jaybird contains functionality to allow the JTA-enabled transaction coordinator to recover the limbo transactions and either commit them or perform a rollback. +For cases where this is not possible, `MaintenanceManager` provides the following methods to perform this in interactive mode: [cols="1m,2",options="header",] |=== @@ -814,11 +812,11 @@ Another type are transactions are those that were finished by "`rollback`" and t Such transactions are marked as "rollback" transactions on the Transaction Inventory Page and this prevents advancing the so-called Oldest Interesting Transaction (OIT), the 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. To solve the issue, Firebird periodically starts a database sweeping process, that traverses all database records, removes the changes made by the rolled back transactions and moves forward the OIT.footnote:[ -For more information please read article by Ann Harrison "`Firebird for the Database Expert: Episode 4 - OAT, OIT, & Sweep`", available, for example, at https://www.ibphoenix.com/resources/documents/design/doc_21] +For more information please read the following article by Ann Harrison, https://web.archive.org/web/20231004130607/https://www.ibphoenix.com/resources/documents/design/doc_21["`Firebird for the Database Expert: Episode 4 - OAT, OIT, & Sweep`"^]] The sweep process is controlled by a threshold parameter, a difference between the Next Transaction and OIT, by default it is set 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. +Alternatively, a DBA can trigger the sweep process manually, regardless of the current difference between Next Transaction and OIT, for example during a maintenance window or hours with low load on the server. The `MaintenanceManager` provides following methods to help with database sweeping: @@ -854,7 +852,7 @@ Please note, only read-only databases can be placed on read-only media, read-wri |setDatabaseDialect(int) |Change the database SQL dialect. -The allowed values can be either 1 or 3. +Allowed values are 1 (deprecated) and 3. |setDefaultCacheBuffer(int) |Change the number of database pages to cache. @@ -872,9 +870,10 @@ However, in case of OS or hardware crashes, the database might get corrupted. a|Set the page fill factor. Firebird leaves 20% of free space on each database page for future record versions. -It is possible to tell Firebird not to reserve the space, this makes sense for read-only databases, since more data fit the page, which increases performance. +It is possible to tell Firebird not to reserve the space. +This makes sense for read-only databases, since more data fit the page, which increases performance. -Possible values are: +Allowed values are: * `PAGE_FILL_FULL` -- do not reserve additional space for future versions; * `PAGE_FILL_RESERVE` -- reserve the free space for future record versions. diff --git a/src/docs/asciidoc/chapters/statements/statements.adoc b/src/docs/asciidoc/chapters/statements/statements.adoc index c4e644e..b2300a5 100644 --- a/src/docs/asciidoc/chapters/statements/statements.adoc +++ b/src/docs/asciidoc/chapters/statements/statements.adoc @@ -59,13 +59,15 @@ statements and returns the number of updated rows. If the specified statement is a query or otherwise produces a result set, an `SQLException` is thrown. * `Statement.execute(String)` -- executes a statement and returns `true` when the statement returned a result set, otherwise an update was executed and `false` is returned. You can use `Statement.getResultSet()` method to get the result of the executed query, or you can use `Statement.getUpdateCount()` when you have executed update statement. ++ +Formally, this method is also used for statements with multiple results (result sets and update counts), but Firebird only supports at most one result set and at most one update count. These `execute` methods have several variants for additional features covered in the reference section <>. A statement is closed by calling the `Statement.close()` method, or by using a try-with-resources which calls `close()` behind the scenes. After a close, the statement object is invalid and cannot be used anymore. -It is allowed to use the same statement object to execute different types of queries one after another. +It is allowed to use the same statement object to execute different types of queries, one after another. 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. [WARNING] @@ -105,7 +107,7 @@ try (Statement stmt = connection.createStatement(); 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 <> 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. +It also shows how to check whether the executed statement modified the 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. [TIP] ====== @@ -142,14 +144,16 @@ try (Statement stmt = connection.createStatement()) { } ---- -It is worth mentioning that according to the JDBC specification `getResultSet()` and `getUpdateCount()` methods can be only called once per result, and in case of using Firebird, that means once per executed statement, since Firebird does not support multiple results from a single statement. -Calling the methods the second time will cause an exception. +According to the JDBC specification, the `getResultSet()` and `getUpdateCount()` methods can be only called once per result. + +[.until]_Jaybird 5.0.5_ In Jaybird 5.0.4 and earlier, calling the `getResultset()` method a second time will throw an exception. + +[.since]_Jaybird 5.0.5_ Since Jaybird 5.0.5, calling `getResultSet()` multiple times will return the same instance of `ResultSet` it returned from the first call to `getResultSet()` or from `executeQuery()`. // TODO May need some revision to address retrieval of update counts after the result set === Statement behind the scenes -The previous examples requires us to discuss the statement object dynamics, its life cycle and how it affects other subsystems in details. +The previous examples requires us to discuss the statement object dynamics, its lifecycle and how it affects other subsystems in details. ==== Statement dynamics @@ -198,13 +202,13 @@ Jaybird could allocate a new statement handle, however the JDBC specification do 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 Firebird server receives a "prepare statement" call, it parses the SQL statement and converts it into the executable form: BLR, or Binary Language Representation. +BLR 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 removed by another application. -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. +However, holding references to 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. @@ -225,7 +229,7 @@ An object that implements this interface represents a precompiled statement that If we use the execution flow described in the "<>" section, it allows us to go directly to 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. +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. @@ -514,7 +518,7 @@ 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. +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. @@ -632,7 +636,7 @@ Firebird 3.0 and earlier did not provide support for such functionality, so Jayb ==== Batch Updates with java.sql.Statement interface 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. +You can add arbitrary `INSERT`/`UPDATE`/`DELETE` or DDL statement to the batch group. Adding a statement that returns a result set is an error. [source,java] @@ -800,7 +804,7 @@ where the outer join is specified as .... ::= {LEFT|RIGHT|FULL} OUTER JOIN - {
| } ON >search condition> + {
| } ON .... An example SQL statement would look like this: @@ -817,7 +821,7 @@ The escaped syntax for stored procedures is described in details in section <