|
| 1 | += JDP-2024-02: Create database through JDBC URL |
| 2 | + |
| 3 | +== Status |
| 4 | + |
| 5 | +* Draft |
| 6 | +* Proposed for: Jaybird 6 |
| 7 | + |
| 8 | +== Type |
| 9 | + |
| 10 | +* Feature-Specification |
| 11 | + |
| 12 | +== Context |
| 13 | + |
| 14 | +In Jaybird 5 and earlier, it is possible to create a new database using the `FBManager` class. |
| 15 | +This requires access to this class, either directly or through reflection. |
| 16 | + |
| 17 | +It would be handy to have a way to create a database through use of the JDBC API only (so no extension APIs or Jaybird-specific classes or methods), for example to create database in third-party JDBC tools or libraries without Jaybird/Firebird specific support. |
| 18 | + |
| 19 | +Although Firebird has a https://firebirdsql.org/file/documentation/html/en/refdocs/fblangref50/firebird-50-language-reference.html[`CREATE DATABASE` statement^], in reality this is partially handled by `fbclient.dll`/`libfbclient.so`, which will parse out information to send an `op_create` request to the server (or the equivalent internal call to the engine in case of embedded), and then use "`execute immediate`" with a modified version of the `CREATE DATABASE` statement on that newly created database for the final initialization. |
| 20 | +This split of responsibilities between client and server is also the reason executing a `CREATE DATABASE` statement on an existing JDBC connection does not work. |
| 21 | + |
| 22 | +Some options of the `CREATE DATABASE` statement have equivalent DPB items, but other items can only be configured with the modified `CREATE DATABASE` statement (or a later `ALTER DATABASE` statement). |
| 23 | +These DPB items can usually also be specified on normal connections, and are applied if the connecting user has admin rights, or is the database owner. |
| 24 | + |
| 25 | +In Firebird, database are isolated from each other, so it is not possible to switch a connection between databases (catalogs). |
| 26 | + |
| 27 | +For comparison, other JDBC drivers offer options like: |
| 28 | + |
| 29 | +* Connection property to create database if it doesn't currently exist: |
| 30 | ++ |
| 31 | +-- |
| 32 | +[horizontal] |
| 33 | +MySQL:: |
| 34 | +Boolean property https://dev.mysql.com/doc/connector-j/en/connector-j-connp-props-connection.html#cj-conn-prop_createDatabaseIfNotExist[`createDatabaseIfNotExist`^] |
| 35 | +-- |
| 36 | +* Automatically create database if it doesn't currently exist: |
| 37 | ++ |
| 38 | +-- |
| 39 | +[horizontal] |
| 40 | +H2:: |
| 41 | +For embedded mode only (see http://h2database.com/html/features.html#database_only_if_exists[Opening a Database Only if it Already Exists^]). |
| 42 | +HSQLDB:: |
| 43 | +For embedded mode only (see http://hsqldb.org/doc/2.0/guide/running-chapt.html#rgc_new_db[Creating a New Database^]). |
| 44 | +-- |
| 45 | +* Support executing `CREATE DATABASE` or equivalent: |
| 46 | ++ |
| 47 | +-- |
| 48 | +[horizontal] |
| 49 | +PostgreSQL:: |
| 50 | +After executing `CREATE DATABASE`, the connection still points to the initial database of the connection. |
| 51 | +Requires switching the catalog with `Connection.setCatalog(...)`. |
| 52 | +SQL Server:: |
| 53 | +Same as PostgreSQL. |
| 54 | +-- |
| 55 | + |
| 56 | +== Decision |
| 57 | + |
| 58 | +Jaybird adds a Boolean connection property `createDatabaseIfNotExist` which defaults to `false`. |
| 59 | +When set to `true`, if the connection cannot be created because the database does not exist, Jaybird will try to create a database. |
| 60 | +This property will be added as a JDBC connection property and as a getter/setter pair for data sources. |
| 61 | + |
| 62 | +In addition, to allow connection properties which are only applied when creating a database, connections properties ending in `@create` (case-sensitive) can override the "`normal`" connection properties with the name before `@create`. |
| 63 | +For data sources, these properties will need to be set as non-standard properties. |
| 64 | + |
| 65 | +The following properties cannot be overridden by `@create` properties: |
| 66 | + |
| 67 | +* `serverName` (alias: `host`) |
| 68 | +* `portNumber` (alias: `port`) |
| 69 | +* `attachObjectName` (alias: `databaseName`, `serviceName`, `database`) |
| 70 | + |
| 71 | +That is, a missing database cannot trigger the creation of a different database (other database name or server). |
| 72 | +Using a different user (with `user@create` and `password@create`) than the normal user, or a different role (with `roleName@create`) is explicitly and intentionally supported. |
| 73 | + |
| 74 | +The "`attach`" otherwise "`create`" decision is made in the XCA layer, specifically -- for the current implementation -- in the constructor of `FBManagedConnection`. |
| 75 | +This may be moved elsewhere in the XCA layer if needed during implementation or at a later time. |
| 76 | + |
| 77 | +=== Rejected design decisions |
| 78 | + |
| 79 | +The following alternatives or options were considered, but rejected: |
| 80 | + |
| 81 | +Support creating a new database with an existing connection:: |
| 82 | +Intercept the `CREATE DATABASE` statement and handle it in a similar manner as `fbclient` does. |
| 83 | +With the following subdivision of solutions: |
| 84 | +Switch the connection to the new database::: |
| 85 | +This might cause confusion/problems, especially if the connection is held in a connection pool (e.g. it is returned to the pool, and the next user assumes it is connected to the original DB, while it is connected to the new DB). |
| 86 | +Keep the connection to the original database::: |
| 87 | +This will cause confusion because the user likely expects that subsequent statements are executed against the new DB. |
| 88 | +With the lack of catalog support, it is also impossible to switch to that new database with the existing connection. |
| 89 | +Terminate/kill connection after execution::: |
| 90 | +Avoids the confusion of the previous points, but is not very user-friendly. |
| 91 | +Allow "`database-less`" connections:: |
| 92 | +In this solution, a (virtual) connection can be made to -- for example -- `jdbc:firebird://localhost/`, and that connection can only be used to create a new database. |
| 93 | +After executing a `CREATE DATABASE` statement, the connection will switch to that new database. |
| 94 | ++ |
| 95 | +This is complex to implement, and results in an inconsistent API between real connections and "`database-less`" connections. |
| 96 | +For example, it allows database creation on one connection, but not another, and the majority of JDBC methods on such connections will not work or not work correctly. |
| 97 | +Allow `CREATE DATABASE` statement in connection property:: |
| 98 | +This would give more flexibility in configuring the newly created database, but would require client-side parsing, and potential confusion with ignoring things like the database name in the statement, and precedence of properties specified in the connection properties vs in the `CREATE DATABASE` statement. |
| 99 | ++ |
| 100 | +This might be an idea for a future improvement or extension. |
| 101 | + |
| 102 | +== Consequences |
| 103 | + |
| 104 | +Jaybird will support database creation through the connection property `createDatabaseIfNotExist`, and allow overriding the normal connection properties by adding those properties with names suffixed with `@create`. |
| 105 | + |
| 106 | +Jaybird may restrict under what conditions or errors it will create a new database. |
| 107 | +Unfortunately, the non-existence of a database is not a clear and specific error, or `isc_io_error`/`335544344` is not specific and possibly other errors maybe raised when the database does not exist, so we may need to refine this in later releases. |
| 108 | +As such, the conditions when creation of a database is attempted is an implementation decision that may change with point releases. |
0 commit comments