Skip to content

Commit

Permalink
H2 Storage backend support for canton jdbc urls with user/password (#…
Browse files Browse the repository at this point in the history
…10523)

* H2 Storage backend support for canton jdbc urls with user/password

The H2 database's JdbcDataSource does not like seeing user/password
properties in the jdbc url raising errors upon hikari connection pool
initialization:

`org.h2.jdbc.JdbcSQLNonTransientConnectionException: Duplicate property "USER"`

expecting to be able to set user and password separately from passing on
the jdbc url.

As h2 is not supported in production and to get canton integration tests past this
resorting to parsing the jdbc url looking for user/password properties, removing
them from the url and instead setting them explicitly on the data source object.

changelog_begin
changelog_end

* Review feedback
  • Loading branch information
oliverse-da authored Aug 10, 2021
1 parent 5cc78f5 commit 511f27c
Showing 1 changed file with 30 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,39 @@ private[backend] object H2StorageBackend
connectionInitHook: Option[Connection => Unit],
)(implicit loggingContext: LoggingContext): DataSource = {
val h2DataSource = new org.h2.jdbcx.JdbcDataSource()
h2DataSource.setUrl(jdbcUrl)

// H2 (org.h2.jdbcx.JdbcDataSource) does not support setting the user/password within the jdbcUrl, so remove
// those properties from the url if present and set them separately. Note that Postgres and Oracle support
// user/password in the URLs, so we don't bother exposing user/password configs separately from the url just for h2
// which is anyway not supported for production. (This also helps run canton h2 participants that set user and
// password.)
val urlNoUser = setKeyValueAndRemoveFromUrl(jdbcUrl, "user", h2DataSource.setUser)
val urlNoUserNoPassword =
setKeyValueAndRemoveFromUrl(urlNoUser, "password", h2DataSource.setPassword)
h2DataSource.setUrl(urlNoUserNoPassword)

InitHookDataSourceProxy(h2DataSource, connectionInitHook.toList)
}

def setKeyValueAndRemoveFromUrl(url: String, key: String, setter: String => Unit): String = {
val separator = ";"
url.toLowerCase.indexOf(separator + key + "=") match {
case -1 => url // leave url intact if key is not found
case indexKeyValueBegin =>
val valueBegin = indexKeyValueBegin + 1 + key.length + 1 // separator, key, "="
val (value, shortenedUrl) = url.indexOf(separator, indexKeyValueBegin + 1) match {
case -1 => (url.substring(valueBegin), url.take(indexKeyValueBegin))
case indexKeyValueEnd =>
(
url.substring(valueBegin, indexKeyValueEnd),
url.take(indexKeyValueBegin) + url.takeRight(url.length - indexKeyValueEnd),
)
}
setter(value)
shortenedUrl
}
}

override def tryAcquire(
lockId: DBLockStorageBackend.LockId,
lockMode: DBLockStorageBackend.LockMode,
Expand Down

0 comments on commit 511f27c

Please sign in to comment.