This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new d7a56f71f0 Replace Derby by HSQLDB as the default database engine for 
embedded data. https://issues.apache.org/jira/browse/SIS-631
d7a56f71f0 is described below

commit d7a56f71f09d5701ae8bce8911abcab01e70b7b0
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Aug 18 19:19:04 2026 +0200

    Replace Derby by HSQLDB as the default database engine for embedded data.
    https://issues.apache.org/jira/browse/SIS-631
---
 .../org/apache/sis/buildtools/gradle/UnoPkg.java   |  2 +-
 endorsed/build.gradle.kts                          |  5 +-
 .../main/org/apache/sis/console/Command.java       | 10 +---
 .../apache/sis/metadata/sql/MetadataSource.java    |  6 +--
 .../apache/sis/metadata/sql/MetadataWriter.java    |  2 +-
 .../metadata/sql/internal/shared/Initializer.java  | 58 ++++++++++----------
 .../sql/internal/shared/LocalDataSource.java       | 16 +++---
 .../metadata/sql/internal/shared/ScriptRunner.java | 63 ++++++++++++++++------
 .../metadata/sql/internal/shared/TypeMapper.java   |  4 +-
 .../org/apache/sis/metadata/sql/TestDatabase.java  |  4 +-
 .../sql/internal/shared/ScriptRunnerTest.java      | 21 +++-----
 .../referencing/factory/sql/EPSGDataAccess.java    |  2 +-
 .../sis/referencing/factory/sql/EPSGFactory.java   | 11 ++--
 .../sis/referencing/factory/sql/EPSGInstaller.java | 26 +++++----
 .../sis/referencing/factory/sql/package-info.java  | 22 ++++----
 .../sis/referencing/factory/TestFactorySource.java |  3 +-
 .../storage/sql/feature/InfoStatementsTest.java    |  6 +--
 .../sis/storage/esri/AsciiGridStoreTest.java       | 12 ++---
 .../main/org/apache/sis/setup/Configuration.java   | 28 ++++++----
 optional/build.gradle.kts                          |  5 +-
 optional/src/org.apache.sis.gui/bundle/bin/sis     |  1 -
 optional/src/org.apache.sis.gui/bundle/bin/sis.bat |  1 -
 optional/src/org.apache.sis.gui/bundle/bin/sisfx   |  1 -
 .../src/org.apache.sis.gui/bundle/bin/sisfx.bat    |  1 -
 optional/src/org.apache.sis.gui/bundle/lib/README  |  2 +-
 optional/src/org.apache.sis.gui/bundle/log/README  |  3 +-
 .../main/module-info.java                          |  6 +--
 .../sis/resources/embedded/EmbeddedResources.java  | 16 +++---
 .../sis/resources/embedded/package-info.java       |  4 +-
 .../resources/embedded/EmbeddedResourcesTest.java  |  2 +-
 .../apache/sis/resources/embedded/Generator.java   | 61 ++++-----------------
 .../main/module-info.java                          |  4 +-
 .../sis/referencing/factory/sql/epsg/README.md     |  4 +-
 33 files changed, 199 insertions(+), 213 deletions(-)

diff --git 
a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/UnoPkg.java 
b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/UnoPkg.java
index a24f82b675..6b4fe561ae 100644
--- a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/UnoPkg.java
+++ b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/UnoPkg.java
@@ -51,7 +51,7 @@ final class UnoPkg extends ZipWriter.JDK {
     static final String MODULE = "org.apache.sis.openoffice";
 
     /**
-     * Module to decompress. We inflate the {@value} module because Derby is 
much slower
+     * Module to decompress. We inflate the {@value} module because queries 
may be slow
      * when using an embedded database in a compressed ZIP file compared to 
flat storage.
      * Since the JAR files are distributed in a ZIP file anyway, inflating 
that file has
      * little impact on the final ZIP file size.
diff --git a/endorsed/build.gradle.kts b/endorsed/build.gradle.kts
index e0fd9f3ec9..ce81a3feda 100644
--- a/endorsed/build.gradle.kts
+++ b/endorsed/build.gradle.kts
@@ -69,8 +69,7 @@ dependencies {
     compileOnly(libs.guava)
     compileOnly(libs.aws.s3)
     compileOnly(drivers.postgres)
-    runtimeOnly(drivers.derby.core)
-    runtimeOnly(drivers.derby.tools)
+    runtimeOnly(drivers.hsql)
 
     // Test dependencies
     testImplementation(tests.junit5)
@@ -138,7 +137,7 @@ fun addExport(args : MutableList<String>, module : String, 
pkg : String, consume
  * The same options are required for both compiling and executing the tests.
  */
 fun addExportForTests(args : MutableList<String>) {
-    addRead(args, "org.apache.sis.metadata",    
"org.apache.derby.tools,com.h2database,org.hsqldb")
+    addRead(args, "org.apache.sis.metadata",    
"org.hsqldb,com.h2database,org.apache.derby.tools")
     addRead(args, "org.apache.sis.referencing", "jama,GeographicLib.Java")
     addRead(args, "org.apache.sis.storage",     "esri.geometry.api")
     addRead(args, "org.apache.sis.storage.xml", "esri.geometry.api")
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java
index 6f2a20455c..a04285dd45 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java
@@ -181,13 +181,11 @@ public final class Command {
 
     /**
      * Loads the logging configuration file if not already done, then 
configures the monoline formatter.
-     * This method performs two main tasks:
+     * This method performs the following tasks:
      *
      * <ol>
      *   <li>If the {@value Initializer#CONFIG_FILE_PROPERTY} is <em>not</em> 
set, then try
      *       to set it to {@code $SIS_HOME/conf/logging.properties} and load 
that file.</li>
-     *   <li>If the {@code "derby.stream.error.file"} system property is not 
defined,
-     *       then try to set it to {@code $SIS_HOME/log/derby.log}.</li>
      *   <li>If the configuration file declares {@link MonolineFormatter} as 
the console formatter,
      *       ensures that the formatter is loaded and resets its colors 
depending on whether X364
      *       seems to be supported.</li>
@@ -204,11 +202,7 @@ public final class Command {
         final String value = System.getenv("SIS_HOME");
         if (value != null) {
             final Path home = Path.of(value).normalize();
-            Path file = home.resolve("log");
-            if (Files.isDirectory(file)) {
-                setPropertyIfAbsent("derby.stream.error.file", 
file.resolve("derby.log"));
-            }
-            file = home.resolve("conf").resolve("logging.properties");
+            Path file = home.resolve("conf").resolve("logging.properties");
             if (Files.isRegularFile(file)) {
                 if (setPropertyIfAbsent(Initializer.CONFIG_FILE_PROPERTY, 
file)) try {
                     Initializer.reload(file);
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
index 183769612e..d2dbe20537 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
@@ -325,14 +325,14 @@ public class MetadataSource implements AutoCloseable {
             } catch (Exception e) {
                 ms = MetadataFallback.INSTANCE;
                 /*
-                 * Derby sometimes wraps SQLException into another 
SQLException.  For making the stack strace a
+                 * Drivers sometimes wrap SQLException into another 
SQLException. For making the stack strace a
                  * little bit simpler, keep only the root cause provided that 
the exception type is compatible.
-                 * If the Derby driver was not found at all, reduce the 
logging level since Derby is optional.
+                 * If the driver was not found at all, reduce the logging 
level since databases are optional.
                  */
                 warning = 
Errors.forLocale(null).createLogRecord(Level.WARNING, 
Errors.Keys.CanNotConnectTo_1, Initializer.JNDI);
                 warning.setThrown(Exceptions.unwrap(e));
                 if (e instanceof ClassNotFoundException) {
-                    warning.setLevel(Level.CONFIG);                         // 
Derby driver not on the module path.
+                    warning.setLevel(Level.CONFIG);         // Driver not on 
the module path.
                 }
                 /*
                  * If the error is transient or has a transient cause, we will 
not save MetadataFallback.INSTANCE
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataWriter.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataWriter.java
index b6dcc0d6d5..fe8990dcec 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataWriter.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataWriter.java
@@ -214,7 +214,7 @@ public class MetadataWriter extends MetadataSource {
                     Errors.Keys.IllegalArgumentClass_2, "metadata", 
metadata.getClass()));
         } catch (SQLException e) {
             /*
-             * Derby sometimes wraps SQLException into another SQLException.  
For making the stack strace a
+             * Drivers sometimes wrap SQLException into another SQLException. 
For making the stack strace a
              * little bit simpler, keep only the root cause provided that the 
exception type is compatible.
              */
             throw new MetadataStoreException(e.getLocalizedMessage(), 
Exceptions.unwrap(e));
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/Initializer.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/Initializer.java
index 1f820d48ff..f44b80b8b8 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/Initializer.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/Initializer.java
@@ -70,8 +70,7 @@ import static 
org.apache.sis.util.internal.shared.MetadataServices.EMBEDDED;
  */
 public abstract class Initializer {
     /**
-     * Name of the database to open in the {@code $SIS_DATA/Databases} 
directory or the directory given by
-     * the {@code derby.system.home} property.
+     * Name of the database to open in the {@code $SIS_DATA/Databases} 
directory.
      *
      * <h4>Dependency note</h4>
      * This field is public for the needs of {@code 
org.apache.sis.referencing.database} module.
@@ -169,7 +168,7 @@ public abstract class Initializer {
         /**
          * Invoked when the JVM is shutting down, or when the Servlet or OSGi 
bundle is uninstalled.
          * This method forgets the data source and unregisters the listener 
from the JNDI context.
-         * Note that there is no need to shutdown a Derby or HDQLDB engine 
since this shutdown is
+         * Note that there is no need to shutdown a HDQLDB or Derby engine 
since this shutdown is
          * only for {@link DataSource} obtained from JNDI context, in which 
case shuting down the
          * database engine should be container job.
          *
@@ -253,27 +252,30 @@ public abstract class Initializer {
      * This method returns the first of the following steps that succeed:
      *
      * <ol class="verbose">
-     *   <li>If a JNDI context exists, use the data source registered under 
the {@code "jdbc/SpatialMetadata"} name.</li>
-     *   <li>Otherwise if a default data source {@linkplain #setDefault has 
been supplied}, use that data source.</li>
-     *   <li>Otherwise if the {@code SIS_DATA} environment variable is defined,
-     *       use the data source for {@code 
"jdbc:derby:$SIS_DATA/Databases/SpatialMetadata"}.
+     *   <li>If a <abbr>JNDI</abbr> context exists,
+     *       use the data source registered under the {@code 
"jdbc/SpatialMetadata"} name.</li>
+     *   <li>Otherwise, if a default data source {@linkplain #setDefault has 
been supplied}, use that data source.</li>
+     *   <li>Otherwise, if the {@code SIS_DATA} environment variable is 
defined, use the following data sources
+     *      if the corresponding database driver is found, in preference order:
+     *       <ol>
+     *         <li>{@code 
"jdbc:hsqldb:file:$SIS_DATA/Databases/SpatialMetadata"} 
(<abbr>HSQL</abbr>),</li>
+     *         <li>{@code "jdbc:derby:$SIS_DATA/Databases/SpatialMetadata"} 
(Derby).</li>
+     *       </ol>
      *       That database will be created if it does not exist. Note that 
this is the only case where
      *       Apache SIS may create the database since it is located in the 
directory managed by Apache SIS.</li>
-     *   <li>Otherwise if the {@code org.apache.sis.referencing.database} 
module is present on the module path,
+     *   <li>Otherwise, if the {@code org.apache.sis.referencing.database} 
module is present on the module path,
      *       use the embedded database.</li>
-     *   <li>Otherwise if the {@code "derby.system.home"} property is defined,
+     *   <li>Otherwise, if the Derby driver is present and the {@code 
"derby.system.home"} property is defined,
      *       use the data source for {@code "jdbc:derby:SpatialMetadata"}.
      *       This database will <strong>not</strong> be created if it does not 
exist.</li>
-     *   <li>Otherwise (no JNDI, no environment variable, no Derby property 
set), {@code null}.</li>
+     *   <li>Otherwise, (no <abbr>JNDI</abbr>, no environment variable, no 
Derby property set), {@code null}.</li>
      * </ol>
      *
-     * The Derby database may be replaced by a HSQLDB database in above steps.
-     *
      * @return the data source for the {@code 
$SIS_DATA/Databases/SpatialMetadata} or equivalent database, or {@code null} if 
none.
      * @throws javax.naming.NamingException     if an error occurred while 
fetching the data source from a JNDI context.
-     * @throws java.net.MalformedURLException   if an error occurred while 
converting the {@code derby.jar} file to URL.
-     * @throws java.lang.ClassNotFoundException if {@code derby.jar} has not 
been found on the JDK installation directory.
-     * @throws java.lang.InstantiationException if an error occurred while 
creating {@code org.apache.derby.jdbc.EmbeddedDataSource}.
+     * @throws java.net.MalformedURLException   if an error occurred while 
converting the <abbr>JAR</abbr> file to URL.
+     * @throws java.lang.ClassNotFoundException if database driver has not 
been found on the JDK installation directory.
+     * @throws java.lang.InstantiationException if an error occurred while 
creating the data source by reflection.
      * @throws java.lang.NoSuchMethodException  if a JDBC bean property has 
not been found on the data source.
      * @throws java.lang.IllegalAccessException if a JDBC bean property of the 
data source is not public.
      * @throws java.lang.reflect.InvocationTargetException if an error 
occurred while setting a data source bean property.
@@ -285,7 +287,7 @@ public abstract class Initializer {
     public static synchronized DataSource getDataSource() throws Exception {
         if (source == null) {
             if (hasJNDI()) try {
-                final Context env = (Context) 
InitialContext.doLookup("java:comp/env");
+                final var env = (Context) 
InitialContext.doLookup("java:comp/env");
                 if (env != null) {
                     source = (DataSource) env.lookup(JNDI);
                     if (env instanceof EventContext) {
@@ -293,7 +295,7 @@ public abstract class Initializer {
                     }
                     return source;
                     /*
-                     * No Derby shutdown hook for DataSource fetched from JNDI.
+                     * No database shutdown hook for DataSource fetched from 
JNDI.
                      * We presume that shutdowns are handled by the container.
                      * We do not clear the `supplier` field in case `source`
                      * is cleaned by the listener.
@@ -320,9 +322,9 @@ public abstract class Initializer {
                 }
             }
             /*
-             * As a fallback, try to open the Derby database located in 
$SIS_DATA/Databases/SpatialMetadata directory.
-             * Only if the SIS_DATA environment variable is not set, verify 
first if the `sis-embedded-data` module is
-             * on the module path. Note that if SIS_DATA is defined and valid, 
it has precedence.
+             * As a fallback, try to open the HSQL database located in 
`$SIS_DATA/Databases/SpatialMetadata.*` files.
+             * Only if the `SIS_DATA` environment variable is not set, verify 
first if the `sis-embedded-data` module
+             * is on the module path. Note that if `SIS_DATA` is defined and 
valid, it has precedence.
              */
             DataSource        embedded   = null;
             LocalDataSource[] candidates = null;
@@ -331,7 +333,7 @@ public abstract class Initializer {
                 embedded = embedded();                  // Check embedded data 
first only if SIS_DATA is not defined.
             }
             if (embedded == null) {
-                candidates = LocalDataSource.create(DATABASE, Dialect.DERBY, 
Dialect.HSQL);     // Null or non-empty.
+                candidates = LocalDataSource.create(DATABASE, Dialect.HSQL, 
Dialect.DERBY);   // Null or non-empty.
                 if (!isEnvClear && (candidates == null || 
candidates[0].create)) {
                     // Check for embedded data only if not already checked and 
if no local database already exists.
                     embedded = embedded();
@@ -379,9 +381,10 @@ public abstract class Initializer {
 
     /**
      * If the {@code org.apache.sis.referencing.database} module is present on 
the module path,
-     * returns the data source for embedded Derby database. Otherwise returns 
{@code null}.
+     * returns the data source for embedded database. Otherwise returns {@code 
null}.
      *
      * @see <a href="https://issues.apache.org/jira/browse/SIS-337";>SIS-337</a>
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-631";>SIS-631</a>
      */
     private static DataSource embedded() {
         for (InstallationResources res : InstallationResources.load()) {
@@ -449,15 +452,14 @@ public abstract class Initializer {
     }
 
     /**
-     * Invoked when the JVM is shutting down, or when the Servlet or OSGi 
bundle is uninstalled.
-     * This method shutdowns the Derby database.
+     * Invoked when the <abbr>JVM</abbr> is shutting down, or when the Servlet 
or OSGi bundle is uninstalled.
+     * This method shutdowns the database.
      *
-     * @throws ReflectiveOperationException if an error occurred while
-     *         setting the shutdown property on the Derby data source.
+     * @throws ReflectiveOperationException if the shutdown process requires 
reflection and that operation failed.
      * @throws SQLException if call to {@link DataSource#unwrap(Class)} failed.
      *         This exception should never happen since {@link #source} should 
always be an instance of
-     *         {@link LocalDataSource} when this method is invoked, and {@link 
SQLException} thrown by
-     *         the database are not propagated here.
+     *         {@link LocalDataSource} when this method is invoked, and {@link 
SQLException} thrown when
+     *         shutting down a Derby database is not propagated here.
      */
     private static synchronized void shutdown() throws 
ReflectiveOperationException, SQLException {
         final DataSource ds = source;
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/LocalDataSource.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/LocalDataSource.java
index 5e218446d6..32ac77d208 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/LocalDataSource.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/LocalDataSource.java
@@ -58,7 +58,7 @@ public final class LocalDataSource implements DataSource, 
Comparable<LocalDataSo
 
     /**
      * The database product to use.
-     * Currently supported values are {@link Dialect#DERBY} and {@link 
Dialect#HSQL}.
+     * Currently supported values are {@link Dialect#HSQL} and {@link 
Dialect#DERBY}.
      */
     private final Dialect dialect;
 
@@ -84,7 +84,7 @@ public final class LocalDataSource implements DataSource, 
Comparable<LocalDataSo
      * the {@link #initialize()} method shall be invoked after construction,
      * unless the caller decides to discard this {@code LocalDataSource} 
instance.
      *
-     * @param  dialect  {@link Dialect#DERBY} or {@link Dialect#HSQL}.
+     * @param  dialect  {@link Dialect#HSQL} or {@link Dialect#DERBY}.
      * @param  dbFile   path to the database to open on the local file system.
      * @param  create   whether the database needs to be created.
      */
@@ -100,7 +100,7 @@ public final class LocalDataSource implements DataSource, 
Comparable<LocalDataSo
      * to {@link #initialize()} after construction.
      *
      * @param  database  database name (usually {@value Initializer#DATABASE}).
-     * @param  dialects  {@link Dialect#DERBY} and/or {@link Dialect#HSQL}.
+     * @param  dialects  {@link Dialect#HSQL} and/or {@link Dialect#DERBY}.
      * @return the local data sources (not yet initialized), or {@code null} 
if none.
      *         If non-null, then the array is guaranteed to contain at least 
one element.
      */
@@ -122,8 +122,8 @@ public final class LocalDataSource implements DataSource, 
Comparable<LocalDataSo
                  * SIS_DATA directory defined: will search only there (no 
search in the Derby home directory).
                  * If a "derby.system.home" property is set, we may be able to 
get a shorter path by making it
                  * relative to Derby home. The intent is to have a nicer URL 
like "jdbc:derby:SpatialMetadata"
-                 * instead of 
"jdbc:derby:/a/long/path/to/SIS/Data/Databases/SpatialMetadata".   In addition
-                 * to making loggings and EPSGDataAccess.getAuthority() output 
nicer, it also reduces the risk
+                 * instead of 
"jdbc:derby:/a/long/path/to/SIS/Data/Databases/SpatialMetadata". In addition to
+                 * making loggings and `EPSGDataAccess.getAuthority()` output 
nicer, it also reduces the risk
                  * of encoding issues if the path contains spaces or non-ASCII 
characters.
                  */
                 Path path = dir.resolve(database);
@@ -175,10 +175,10 @@ public final class LocalDataSource implements DataSource, 
Comparable<LocalDataSo
     static DataSource wrap(final DataSource source) {
         final Dialect dialect;
         final String cn = source.getClass().getName();
-        if (cn.startsWith("org.apache.derby.")) {
-            dialect = Dialect.DERBY;
-        } else if (cn.startsWith("org.hsqldb.")) {
+        if (cn.startsWith("org.hsqldb.")) {
             dialect = Dialect.HSQL;
+        } else if (cn.startsWith("org.apache.derby.")) {
+            dialect = Dialect.DERBY;
         } else {
             return source;
         }
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/ScriptRunner.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/ScriptRunner.java
index c681adf465..589d17723a 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/ScriptRunner.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/ScriptRunner.java
@@ -60,7 +60,7 @@ public class ScriptRunner implements AutoCloseable {
      * this keyword must be last before the comma in the declaration of a 
column. Example:
      *
      * {@snippet lang="sql" :
-     * coord_sys_name VARCHAR(254) NOT NULL COLLATE "Ignore Accent and Case",
+     * coord_sys_name VARCHAR(254) COLLATE "Ignore Accent and Case" NOT NULL,
      * }
      *
      * @see #editTableCreation(StringBuilder)
@@ -125,7 +125,7 @@ public class ScriptRunner implements AutoCloseable {
      *
      * @see #addReplacement(String, String)
      */
-    private final Map<String,String> replacements;
+    private final Map<String, String> replacements;
 
     /**
      * The quote character for identifiers actually used in the database,
@@ -155,7 +155,7 @@ public class ScriptRunner implements AutoCloseable {
 
     /**
      * {@code true} if the database supports collations in the way used by 
Apache <abbr>SIS</abbr>.
-     * The way to use collations vary a lot between databases, so the 
"<abbr>SIS</abbr> way" is the
+     * The way to use collations varies a lot between databases, so the 
"<abbr>SIS</abbr> way" is the
      * PostgreSQL way for now. A value of {@code false} does not necessarily 
means that the database
      * does not support collations at all, but the database does not support 
{@code CREATE COLLATION}
      * statements and collations declared in column definitions.
@@ -164,10 +164,25 @@ public class ScriptRunner implements AutoCloseable {
      */
     protected final boolean isCollationSupported;
 
+    /**
+     * Whether the database supports the creation of user-defined collations.
+     * If {@code false} while {@link #isCollationSupported} is {@code true},
+     * then the database supports only a hard-coded list of collations.
+     */
+    protected final boolean canCreateCollations;
+
+    /**
+     * The schema which has been created and to delete in case of failure, or 
{@code null} if none.
+     * Used for rolling back in case of failure. This is set to {@code null} 
after successful completion.
+     * In principle, {@link Connection#rollback()} should be sufficient, but 
it appears to not be the case
+     * with all databases.
+     */
+    private String schemaToDelete;
+
     /**
      * The maximum number of rows allowed per {@code "INSERT"} statement.
      * This is 1 if the database does not support multi-rows insertion.
-     * For other database, this is set to an arbitrary "reasonable" value 
since attempts to insert
+     * For other database, this is set to an arbitrary reasonable value since 
attempts to insert
      * too many rows with a single statement on Derby database cause a {@link 
StackOverflowError}.
      */
     private final int maxRowsPerInsert;
@@ -184,7 +199,8 @@ public class ScriptRunner implements AutoCloseable {
      *
      * <ul>
      *   <li>{@link #isEnumTypeSupported} for {@code "CREATE TYPE …"} or 
{@code "CREATE CAST …"} statements.</li>
-     *   <li>{@link #isCollationSupported} for {@code "CREATE COLLATION …"} 
statements.</li>
+     *   <li>{@link #canCreateCollations} for {@code "CREATE COLLATION …"} 
statements.</li>
+     *   <li>{@link #isCollationSupported} for {@value #COLLATE} statements 
after column definitions.</li>
      *   <li>{@link Dialect#supportsGrantUsageOnSchema} for {@code "GRANT 
USAGE ON SCHEMA …"} statements.</li>
      *   <li>{@link Dialect#supportsGrantSelectOnTable} for {@code "GRANT 
SELECT ON TABLE …"} statements.</li>
      *   <li>{@link Dialect#supportsComment} for {@code "COMMENT ON …"} 
statements.</li>
@@ -244,19 +260,19 @@ public class ScriptRunner implements AutoCloseable {
         metadata         = connection.getMetaData();
         dialect          = Dialect.guess(metadata);
         identifierQuote  = metadata.getIdentifierQuoteString();
+        statement        = connection.createStatement();
         if (schemaToCreate != null && 
metadata.supportsSchemasInTableDefinitions()) {
-            try (Statement stmt = connection.createStatement()) {
-                stmt.executeUpdate("CREATE SCHEMA " + identifierQuote + 
schemaToCreate + identifierQuote);
-                if (dialect.supportsGrantUsageOnSchema()) {
-                    stmt.executeUpdate("GRANT USAGE ON SCHEMA " + 
identifierQuote + schemaToCreate + identifierQuote + " TO PUBLIC");
-                }
+            statement.executeUpdate("CREATE SCHEMA " + identifierQuote + 
schemaToCreate + identifierQuote);
+            if (dialect.supportsGrantUsageOnSchema()) {
+                statement.executeUpdate("GRANT USAGE ON SCHEMA " + 
identifierQuote + schemaToCreate + identifierQuote + " TO PUBLIC");
             }
+            schemaToDelete = schemaToCreate;
             connection.setSchema(schemaToCreate);   // Must be set before the 
next call to `createStatement()` below.
         }
-        statement = connection.createStatement();
         switch (dialect) {
             default: {
                 isEnumTypeSupported  = false;
+                canCreateCollations  = false;
                 isCollationSupported = false;
                 break;
             }
@@ -264,11 +280,13 @@ public class ScriptRunner implements AutoCloseable {
                 final int version = metadata.getDatabaseMajorVersion();
                 isEnumTypeSupported  = (version >=  9);
                 isCollationSupported = (version >= 18);     // ICU collation 
provider available since version 15, except LIKE support which is since 18.
+                canCreateCollations  = isCollationSupported;
                 break;
             }
             case HSQL: {
                 isEnumTypeSupported  = false;
-                isCollationSupported = false;
+                canCreateCollations  = false;
+                isCollationSupported = true;
                 /*
                  * HSQLDB stores tables in memory by default. For storing the 
tables on files, we have to
                  * use "CREATE CACHED TABLE" statement, which is 
HSQL-specific. For avoiding SQL dialect,
@@ -288,7 +306,7 @@ public class ScriptRunner implements AutoCloseable {
         if (!isEnumTypeSupported) {
             addStatementToSkip("CREATE\\s+(?:TYPE|CAST)\\s+.*");
         }
-        if (!isCollationSupported) {
+        if (!canCreateCollations) {
             addStatementToSkip("CREATE\\s+COLLATION\\s+.*");
         }
         if (!dialect.supportsAllGrants()) {
@@ -325,7 +343,8 @@ public class ScriptRunner implements AutoCloseable {
      *
      * <ul>
      *   <li>{@code "CREATE TYPE …"} or {@code "CREATE CAST …"} if {@link 
#isEnumTypeSupported} is {@code false}.</li>
-     *   <li>{@code "CREATE COLLATION …"} if {@link #isCollationSupported} is 
{@code false}.</li>
+     *   <li>{@code "CREATE COLLATION …"} if {@link #canCreateCollations} is 
{@code false}.</li>
+     *   <li>{@value #COLLATE} after column definitions if {@link 
#isCollationSupported} is  {@code false}.</li>
      *   <li>{@code "GRANT USAGE ON SCHEMA …"} if {@link 
Dialect#supportsGrantUsageOnSchema} is {@code false}.</li>
      *   <li>{@code "GRANT SELECT ON TABLE …"} if {@link 
Dialect#supportsGrantSelectOnTable} is {@code false}.</li>
      *   <li>{@code "COMMENT ON …"} if {@link Dialect#supportsComment} is 
{@code false}.</li>
@@ -689,7 +708,7 @@ parseLine:  while (pos < length) {
      * {@snippet lang="sql" :
      *   CREATE TABLE "Coordinate System" (
      *     coord_sys_code INTEGER NOT NULL,
-     *     coord_sys_name VARCHAR(254) NOT NULL COLLATE "Ignore Accent and 
Case",
+     *     coord_sys_name VARCHAR(254) COLLATE "Ignore Accent and Case" NOT 
NULL,
      *     CONSTRAINT pk_coordinatesystem PRIMARY KEY (coord_sys_code))
      *   }
      *
@@ -822,6 +841,15 @@ parseLine:  while (pos < length) {
         return count;
     }
 
+    /**
+     * Confirms that the schema specified at construction time should not be 
deleted.
+     * This method must be invoked before {@link #close()} if the script 
completed successfully,
+     * unless no schema was specified at construction time in which case 
invoking this method is optional.
+     */
+    public void keepCreatedSchema() {
+        schemaToDelete = null;
+    }
+
     /**
      * Closes the statement used by this runner. Note that this method does 
not close the connection
      * given to the constructor; this connection still needs to be closed 
explicitly by the caller.
@@ -830,6 +858,11 @@ parseLine:  while (pos < length) {
      */
     @Override
     public void close() throws SQLException {
+        final String schema = schemaToDelete;
+        if (schema != null) {
+            schemaToDelete = null;
+            statement.executeUpdate("DROP SCHEMA " + identifierQuote + schema 
+ identifierQuote + " CASCADE");
+        }
         statement.close();
     }
 
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/TypeMapper.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/TypeMapper.java
index 74ae288d4b..fdb406e50b 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/TypeMapper.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/internal/shared/TypeMapper.java
@@ -28,10 +28,10 @@ import java.sql.JDBCType;
 final class TypeMapper {
     /**
      * A list of Java classes to be mapped to SQL types. We do not want to map 
every SQL types,
-     * but only the ones which are of interest for the Apache SIS metadata 
implementation.
+     * but only the ones which are of interest for the Apache <abbr>SIS</abbr> 
metadata implementation.
      * The types will be tested in the order they are declared, so the last 
declarations are fallbacks.
      *
-     * <p>The types declared here matches both the Derby and PostgreSQL 
mapping.</p>
+     * <p>The types declared here matches both the PostgreSQL and Derby 
mapping.</p>
      */
     private static final TypeMapper[] TYPES = {
         new TypeMapper(Boolean.class, JDBCType.BOOLEAN),
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
index 17a86b73b8..bd9d419c42 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
@@ -87,7 +87,7 @@ public class TestDatabase implements AutoCloseable {
 
     /**
      * Data source for connection to an alternative database for testing 
purpose.
-     * If {@code null}, an in-memory Derby database will be used.
+     * If {@code null}, a {@linkplain #create(String) default in-memory 
database} will be used.
      *
      * This field is occasionally set to a non-null value (e.g. a connection 
to a PostgreSQL database) only for
      * debugging purpose. In such case, it is developer responsibility to 
ensure that the appropriate driver is
@@ -337,7 +337,7 @@ public class TestDatabase implements AutoCloseable {
     }
 
     /**
-     * Drops the test schema (PostgreSQL) or the test database (Derby) after 
usage.
+     * Drops the test schema (PostgreSQL) or the test database (HSQL, H2, 
Derby) after usage.
      *
      * @throws SQLException if an error occurred while dropping the test data.
      */
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/internal/shared/ScriptRunnerTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/internal/shared/ScriptRunnerTest.java
index ecceff1bf7..260d8de813 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/internal/shared/ScriptRunnerTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/internal/shared/ScriptRunnerTest.java
@@ -41,7 +41,6 @@ public final class ScriptRunnerTest extends TestCase {
 
     /**
      * Tests {@link ScriptRunner} with the default database engine used by 
Apache <abbr>SIS</abbr>.
-     * This method delegates its work to all other methods in this class that 
expect a {@link ScriptRunner} argument.
      *
      * @throws SQLException if an error occurred while executing the script 
runner.
      */
@@ -51,14 +50,15 @@ public final class ScriptRunnerTest extends TestCase {
              Connection c = db.source.getConnection())
         {
             final var sr = new ScriptRunner(c, null, 3);
-            testSupportedFlags(sr);
+            assertFalse(sr.isEnumTypeSupported);
+            assertFalse(sr.canCreateCollations);
+            assertTrue (sr.isCollationSupported);
             testRegularExpressions(sr);
         }
     }
 
     /**
      * Tests {@link ScriptRunner} with an in-memory Derby database.
-     * This method delegates its work to all other methods in this class that 
expect a {@link ScriptRunner} argument.
      *
      * @throws SQLException if an error occurred while executing the script 
runner.
      */
@@ -68,22 +68,13 @@ public final class ScriptRunnerTest extends TestCase {
              Connection c = db.source.getConnection())
         {
             final var sr = new ScriptRunner(c, null, 3);
-            testSupportedFlags(sr);
+            assertFalse(sr.isEnumTypeSupported);
+            assertFalse(sr.canCreateCollations);
+            assertFalse(sr.isCollationSupported);
             testRegularExpressions(sr);
         }
     }
 
-    /**
-     * Verifies the values of {@code is*Supported} flags in the given script 
runner.
-     *
-     * @param  sr  the script runner for which to verify flag values.
-     */
-    @TestStep
-    public static void testSupportedFlags(final ScriptRunner sr) {
-        assertFalse(sr.isEnumTypeSupported);
-        assertFalse(sr.isCollationSupported);
-    }
-
     /**
      * Verifies the regular expressions used by the script runner.
      * This method tests the values returned by {@link 
ScriptRunner#isSupported(CharSequence)}
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 172b10d088..90d8ff5ca0 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -160,7 +160,7 @@ import org.opengis.referencing.ObjectDomain;
  * @author  Matthias Basler
  * @author  Andrea Aime (TOPP)
  * @author  Johann Sorel (Geomatys)
- * @version 1.6
+ * @version 1.7
  *
  * @see <a 
href="https://sis.apache.org/tables/CoordinateReferenceSystems.html";>List of 
authority codes</a>
  *
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGFactory.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGFactory.java
index 58e61128a3..70fcbd36f2 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGFactory.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGFactory.java
@@ -57,7 +57,7 @@ import org.apache.sis.util.resources.Messages;
  *
  * <p>If no data source has been specified to the constructor, then {@code 
EPSGFactory} searches for a
  * default data source in JNDI, or in the directory given by the {@code 
SIS_DATA} environment variable,
- * or in the directory given by the {@code "derby.system.home"} property, in 
that order.
+ * or in the directory given by the {@code "derby.system.home"} property (if 
using Derby), in that order.
  * See the {@linkplain org.apache.sis.referencing.factory.sql package 
documentation} for more information.</p>
  *
  * <h2>EPSG dataset installation</h2>
@@ -74,7 +74,7 @@ import org.apache.sis.util.resources.Messages;
  * subclass.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
  *
  * @see EPSGDataAccess
  * @see SQLTranslator
@@ -390,7 +390,7 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
             if (autoCommit) {
                 connection.setAutoCommit(false);
             }
-            try (EPSGInstaller installer = new EPSGInstaller(connection, 
schema)) {
+            try (var installer = new EPSGInstaller(connection, schema)) {
                 try {
                     success = installer.run(scriptProvider, locale);
                 } catch (IOException | SQLException e) {
@@ -422,7 +422,7 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
                                           : Messages.Keys.NoDataSourceFound_1, 
Constants.EPSG);
             }
             /*
-             * Derby sometimes wraps SQLException into another SQLException.  
For making the stack strace a
+             * Drivers sometimes wrap SQLException into another SQLException. 
For making the stack strace a
              * little bit simpler, keep only the root cause provided that the 
exception type is compatible.
              */
             var exception = new UnavailableFactoryException(message, 
Exceptions.unwrap(failure));
@@ -450,6 +450,7 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
      *         This exception usually has a {@link SQLException} as its cause.
      */
     @Override
+    @SuppressWarnings("UseSpecificCatch")
     protected EPSGDataAccess newDataAccess() throws FactoryException {
         UnavailableFactoryException exception;
         Connection connection = null;
@@ -494,7 +495,7 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
                 throw (FactoryException) e;
             }
             /*
-             * Derby sometimes wraps SQLException into another SQLException.  
For making the stack strace a
+             * Drivers sometimes wraps SQLException into another SQLException. 
For making the stack strace a
              * little bit simpler, keep only the root cause provided that the 
exception type is compatible.
              */
             exception = new UnavailableFactoryException(canNotUse(e), 
Exceptions.unwrap(e));
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGInstaller.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGInstaller.java
index b6cd4056be..cd8f9a434c 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGInstaller.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGInstaller.java
@@ -16,16 +16,17 @@
  */
 package org.apache.sis.referencing.factory.sql;
 
-import java.util.Locale;
 import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.concurrent.TimeUnit;
 import java.io.IOException;
 import java.io.FileNotFoundException;
 import java.io.BufferedReader;
 import java.sql.Connection;
 import java.sql.SQLException;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
 import org.apache.sis.util.internal.shared.Constants;
 import org.apache.sis.util.resources.Messages;
 import org.apache.sis.util.logging.Logging;
@@ -47,7 +48,8 @@ import org.apache.sis.setup.InstallationResources;
 final class EPSGInstaller extends ScriptRunner {
     /**
      * The quoted identifiers to replace, or an empty map if none.
-     * Used for replacing enumeration types when not supported by the target 
database.
+     * Used for replacing enumeration types and custom collections
+     * when not supported by the target database.
      */
     private final Map<String, String> identifierReplacements;
 
@@ -68,15 +70,17 @@ final class EPSGInstaller extends ScriptRunner {
      */
     public EPSGInstaller(final Connection connection, final String schema) 
throws SQLException {
         super(connection, schema == null ? Constants.EPSG : schema.isEmpty() ? 
null : schema, 100);
-        if (isEnumTypeSupported) {
-            identifierReplacements = Map.of();
-        } else {
-            identifierReplacements = Map.of(
+        identifierReplacements = new HashMap<>();
+        if (!isEnumTypeSupported) {
+            identifierReplacements.putAll(Map.of(
                     "Datum Kind",        "VARCHAR(16)",    // Original: 
VARCHAR(24) for column "datum_type".
                     "CRS Kind",          "VARCHAR(13)",    // Original: 
VARCHAR(24) for column "coord_ref_sys_kind".
                     "CS Kind",           "VARCHAR(15)",    // Original: 
VARCHAR(24) for column "coord_sys_type".
                     "Supersession Type", "VARCHAR(12)",    // Original: 
VARCHAR(50) for column "supersession_type".
-                    "Table Name",        "VARCHAR(36)");   // Original: 
VARCHAR(80) for columns "object_table_name".
+                    "Table Name",        "VARCHAR(36)"));  // Original: 
VARCHAR(80) for columns "object_table_name".
+        }
+        if (!canCreateCollations) {
+            identifierReplacements.put("Ignore Accent and Case", "\"English 
0\"");
         }
     }
 
@@ -180,6 +184,8 @@ final class EPSGInstaller extends ScriptRunner {
                 Messages.Keys.InsertDuration_2,
                 numRows,
                 time / (float) Constants.NANOS_PER_SECOND));
+
+        keepCreatedSchema();
         return true;
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/package-info.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/package-info.java
index 3df5fafcea..7a366ea7a1 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/package-info.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/package-info.java
@@ -24,28 +24,28 @@
  *
  *
  * <h2>Connection to the database</h2>
- * Apache SIS uses the Apache Derby database by default. However, connection 
to the <abbr>EPSG</abbr>
- * dataset should work with any <abbr>SQL</abbr> compliant databases (tested 
on PostgreSQL and HSQL).
+ * Apache <abbr>SIS</abbr> uses the HSQLDB database by default. However, 
connection to the <abbr>EPSG</abbr>
+ * dataset should work with any <abbr>SQL</abbr> compliant databases (tested 
on PostgreSQL, H2 and Derby).
  * The database connection is obtained by the first of the following data 
sources which is found:
  *
  * <ol>
- *   <li>If a {@linkplain javax.naming.InitialContext JNDI context} exists,
+ *   <li>If a {@linkplain javax.naming.InitialContext <abbr>JNDI</abbr> 
context} exists,
  *       the {@link javax.sql.DataSource} registered under the {@code 
"java:comp/env/jdbc/SpatialMetadata"} name.</li>
  *   <li>If the {@code SIS_DATA} {@linkplain java.lang.System#getenv(String) 
environment variable} is defined,
- *       a JDBC connection for the {@code 
"jdbc:derby:$SIS_DATA/Databases/SpatialMetadata"} URL.</li>
- *   <li>If the {@code "derby.system.home"} {@linkplain 
java.lang.System#getProperty(String) property} is defined,
- *       a JDBC connection for the {@code "jdbc:derby:SpatialMetadata"} 
URL.</li>
+ *       a <abbr>JDBC</abbr> connection for the {@code 
"jdbc:hsqldb:file:$SIS_DATA/Databases/SpatialMetadata"} <abbr>URL</abbr>.</li>
+ *   <li>If Derby is used and the {@code "derby.system.home"} {@linkplain 
java.lang.System#getProperty(String) property}
+ *       is defined, a <abbr>JDBC</abbr> connection for the {@code 
"jdbc:derby:SpatialMetadata"} <abbr>URL</abbr>.</li>
  *   <li>If the {@code org.apache.sis.referencing.database} module is present 
on the module path,
  *       a read-only connection to the database in the JAR file.</li>
  * </ol>
  *
- * In choice 1, the JDBC driver must be provided by the application container 
(e.g. Apache Tomcat).
- * With other choices, an Apache Derby driver should be available on the 
module path.
+ * In choice 1, the <abbr>JDBC</abbr> driver must be provided by the 
application container (e.g. Apache Tomcat).
+ * With other choices, a <abbr>HSQLDB</abbr> or Apache Derby driver should be 
available on the module path.
  *
  *
- * <h2>The EPSG dataset</h2>
+ * <h2>The <abbr>EPSG</abbr> dataset</h2>
  * A widely-used factory is the <a href="https://epsg.org/";>EPSG geodetic 
dataset</a>.
- * EPSG codes are numerical identifiers.
+ * <abbr>EPSG</abbr> codes are numerical identifiers.
  * For example, {@code "EPSG:4326"} is the EPSG identifier for the <q>WGS 
84</q> geographic CRS.
  * As an extension, the Apache SIS implementation accepts names as well as 
numeric identifiers.
  * For example, the two following method calls fetch the same object:
@@ -83,7 +83,7 @@
  * @author  Jody Garnett (Refractions)
  * @author  Didier Richard (IGN)
  * @author  John Grange
- * @version 1.6
+ * @version 1.7
  *
  * @see org.apache.sis.metadata.sql
  *
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/TestFactorySource.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/TestFactorySource.java
index bae2ecf671..2acd0b2a8f 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/TestFactorySource.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/TestFactorySource.java
@@ -65,7 +65,8 @@ import static org.opengis.test.Assertions.assertBetween;
  */
 public final class TestFactorySource {
     /**
-     * Whether to use PostgreSQL instead of Derby for the tests. This field 
should be {@code false};
+     * Whether to use PostgreSQL instead of the default database for the tests.
+     * This field should be {@code false};
      * the {@code true} value is used only for temporarily debugging of 
PostgreSQL-specific features.
      * It is developer responsibility to setup a {@code "SpatialMetadata"} 
database on the local host.
      * This method differs from {@link 
org.apache.sis.metadata.sql.TestDatabase} by querying a permanent
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
index 86c9b33806..1cc0eb912d 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
@@ -56,7 +56,7 @@ import org.apache.sis.referencing.datum.HardCodedDatum;
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public final class InfoStatementsTest extends TestCase {
     /**
-     * A in-memory database on Derby.
+     * A in-memory database using the default embedded database.
      */
     private final TestDatabase test;
 
@@ -101,7 +101,7 @@ public final class InfoStatementsTest extends TestCase {
     public void initialize() throws Exception {
         test.executeSQL(List.of(createSpatialRefSys()));
         connection = test.source.getConnection();
-        database = new Database<>(test.source, connection.getMetaData(), 
Dialect.DERBY,
+        database = new Database<>(test.source, connection.getMetaData(), 
Dialect.HSQL,
                                   Geometries.factory(GeometryLibrary.JAVA2D), 
null,
                                   new StoreListeners(null, new 
DataStoreMock("Unused")), null);
         /*
@@ -123,7 +123,7 @@ public final class InfoStatementsTest extends TestCase {
     @Test
     public void testFindSRID() throws Exception {
         final Connection c = connection;
-        try (InfoStatements info = new InfoStatements(database, c)) {
+        try (var info = new InfoStatements(database, c)) {
             c.setReadOnly(true);
             final CoordinateReferenceSystem crs = HardCodedCRS.WGS84;
             var e = assertThrows(DataStoreReferencingException.class, () -> 
info.findSRID(crs));
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/esri/AsciiGridStoreTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/esri/AsciiGridStoreTest.java
index 01d750aa53..a41fb4c69f 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/esri/AsciiGridStoreTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/esri/AsciiGridStoreTest.java
@@ -74,7 +74,7 @@ public final class AsciiGridStoreTest extends TestCase {
      */
     @Test
     public void testProbeContent() throws DataStoreException {
-        final AsciiGridStoreProvider p = new AsciiGridStoreProvider();
+        final var p = new AsciiGridStoreProvider();
         final ProbeResult r = p.probeContent(testData());
         assertTrue(r.isSupported());
         assertEquals("text/plain", r.getMimeType());
@@ -89,12 +89,12 @@ public final class AsciiGridStoreTest extends TestCase {
      */
     @Test
     public void testMetadata() throws DataStoreException {
-        try (AsciiGridStore store = new AsciiGridStore(null, testData(), 
true)) {
+        try (final var store = new AsciiGridStore(null, testData(), true)) {
             assertEquals("grid", store.getIdentifier().get().toString());
             final Metadata metadata = store.getMetadata();
             /*
              * Format information is hard-coded in "SpatialMetadata" database. 
Complete string should
-             * be "ESRI ArcInfo ASCII Grid format" but it depends on the 
presence of Derby dependency.
+             * be "ESRI ArcInfo ASCII Grid format" but it depends on the 
presence of metadata database.
              */
             final Identification id = 
assertSingleton(metadata.getIdentificationInfo());
             final String format = assertSingletonResourceFormat(id);
@@ -120,7 +120,7 @@ public final class AsciiGridStoreTest extends TestCase {
      */
     @Test
     public void testRead() throws DataStoreException {
-        try (AsciiGridStore store = new AsciiGridStore(null, testData(), 
true)) {
+        try (final var store = new AsciiGridStore(null, testData(), true)) {
             final List<Category> categories = 
assertSingleton(store.getSampleDimensions()).getCategories();
             assertEquals(2, categories.size());
             assertEquals(   -2, 
categories.get(0).getSampleRange().getMinDouble(), 1);
@@ -156,7 +156,7 @@ public final class AsciiGridStoreTest extends TestCase {
     @Test
     public void testFileSet() throws DataStoreException, IOException {
         AsciiGridStore.FileSet fileset;
-        try (AsciiGridStore store = new AsciiGridStore(null, testData(), 
true)) {
+        try (var store = new AsciiGridStore(null, testData(), true)) {
             fileset = store.getFileSet().orElseThrow();
         }
         final Path source = fileset.getPaths().iterator().next();
@@ -176,7 +176,7 @@ public final class AsciiGridStoreTest extends TestCase {
              * In order to test the delete operation, we need to open a new 
data store on the file
              * that we just copied. Otherwise, `fileset.delete()` would delete 
the original file.
              */
-            try (AsciiGridStore store = new AsciiGridStore(null,  new 
StorageConnector(target), true)) {
+            try (var store = new AsciiGridStore(null, new 
StorageConnector(target), true)) {
                 fileset = store.getFileSet().orElseThrow();
             }
             fileset.delete();
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java
index 6eb3f95079..9a85f62605 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java
@@ -57,7 +57,7 @@ import org.apache.sis.util.internal.shared.MetadataServices;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
  * @since   1.0
  */
 public final class Configuration {
@@ -84,21 +84,27 @@ public final class Configuration {
     }
 
     /**
-     * Returns the data source for the SIS-wide "SpatialMetadata" database.
+     * Returns the data source for the <abbr>SIS</abbr>-wide "SpatialMetadata" 
database.
      * This method returns the first of the following steps that succeed:
      *
-     * <ol>
-     *   <li>If a JNDI context exists, use the data source registered under 
the {@code "jdbc/SpatialMetadata"} name.</li>
-     *   <li>Otherwise if a default data source {@linkplain #setDatabase has 
been supplied}, use that data source.</li>
-     *   <li>Otherwise if the {@code SIS_DATA} environment variable is defined,
-     *       use the data source for {@code 
"jdbc:derby:$SIS_DATA/Databases/SpatialMetadata"}.
+     * <ol class="verbose">
+     *   <li>If a <abbr>JNDI</abbr> context exists,
+     *       use the data source registered under the {@code 
"jdbc/SpatialMetadata"} name.</li>
+     *   <li>Otherwise, if a default data source {@linkplain #setDatabase has 
been supplied}, use that data source.</li>
+     *   <li>Otherwise, if the {@code SIS_DATA} environment variable is 
defined, use the following data sources
+     *      if the corresponding database driver is found, in preference order:
+     *       <ol>
+     *         <li>{@code 
"jdbc:hsqldb:file:$SIS_DATA/Databases/SpatialMetadata"} 
(<abbr>HSQL</abbr>),</li>
+     *         <li>{@code "jdbc:derby:$SIS_DATA/Databases/SpatialMetadata"} 
(Derby).</li>
+     *       </ol>
      *       That database will be created if it does not exist. Note that 
this is the only case where
      *       Apache SIS may create the database since it is located in the 
directory managed by Apache SIS.</li>
-     *   <li>Otherwise if the {@code org.apache.sis.referencing.database} 
module is present on the module path,
+     *   <li>Otherwise, if the {@code org.apache.sis.referencing.database} 
module is present on the module path,
      *       use the embedded database.</li>
-     *   <li>Otherwise if the "{@systemProperty derby.system.home}" property 
is defined,
-     *       use the data source for {@code "jdbc:derby:SpatialMetadata"} 
database.
+     *   <li>Otherwise, if the Derby driver is present and the {@code 
"derby.system.home"} property is defined,
+     *       use the data source for {@code "jdbc:derby:SpatialMetadata"}.
      *       This database will <strong>not</strong> be created if it does not 
exist.</li>
+     *   <li>Otherwise, (no <abbr>JNDI</abbr>, no environment variable, no 
Derby property set), empty.</li>
      * </ol>
      *
      * @return the data source for the {@code "SpatialMetadata"} database.
@@ -163,7 +169,7 @@ public final class Configuration {
      * This method may be useful in embedded environments that do not allow 
the use of shutdown hooks,
      * or when waiting for the <abbr>JVM</abbr> shutdown is overly 
conservative.
      *
-     * <h4>Complete shutdown</h4>
+     * <h4>Complete shutdown of Derby</h4>
      * This method shutdowns only the databases used by Apache 
<abbr>SIS</abbr>.
      * If Apache Derby is used for the <abbr>EPSG</abbr> database, some Derby 
daemon threads may still be running.
      * Those daemons can be ignored in standalone applications, but may need 
to be stopped in embedded environments.
diff --git a/optional/build.gradle.kts b/optional/build.gradle.kts
index ea435c7cb6..12895d9093 100644
--- a/optional/build.gradle.kts
+++ b/optional/build.gradle.kts
@@ -68,8 +68,7 @@ dependencies {
     runtimeOnly   (files("${mainDepPath}/org.apache.sis.storage.geotiff"))
     runtimeOnly   
(files("${mainDepPath}/org.apache.sis.storage.earthobservation"))
     api           (files("${mainDepPath}/org.apache.sis.portrayal"))
-    api           (drivers.derby.core)
-    api           (drivers.derby.tools)
+    api           (drivers.hsql)
 
     // Test dependencies
     testImplementation(drivers.postgres)
@@ -269,7 +268,7 @@ publishing {
             pom {
                 name        = "Data in embedded environment"
                 description = "Provides non-free data, including the EPSG 
geodetic dataset, in a single read-only JAR file. " +
-                              "This module contains a copy of EPSG geodetic 
dataset in an embedded Apache Derby database. " +
+                              "This module contains a copy of EPSG geodetic 
dataset in an embedded HSQLDB database. " +
                               "Having this artifact on the module path avoid 
the need to set the 'SIS_DATA' environment variable " +
                               "for using the Coordinate Reference Systems 
(CRS) and Coordinate Operations defined by EPSG. " +
                               "EPSG is maintained by the IOGP Surveying &amp; 
Positioning Committee and reproduced in this module " +
diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sis 
b/optional/src/org.apache.sis.gui/bundle/bin/sis
index 7ebd141e66..e82a73d56a 100755
--- a/optional/src/org.apache.sis.gui/bundle/bin/sis
+++ b/optional/src/org.apache.sis.gui/bundle/bin/sis
@@ -30,6 +30,5 @@ export COLUMNS
 java --module-path 
"$BASE_DIR/lib:$BASE_DIR/lib/app/org.apache.sis.console.jar" \
      
-Djava.util.logging.config.class="org.apache.sis.util.logging.Initializer" \
      -Djava.util.logging.config.file="$BASE_DIR/conf/logging.properties" \
-     -Dderby.stream.error.file="$BASE_DIR/log/derby.log" \
      --module org.apache.sis.console/org.apache.sis.console.Command \
      $SIS_OPTS "$@"
diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sis.bat 
b/optional/src/org.apache.sis.gui/bundle/bin/sis.bat
index 25a55363b3..dc449ce141 100644
--- a/optional/src/org.apache.sis.gui/bundle/bin/sis.bat
+++ b/optional/src/org.apache.sis.gui/bundle/bin/sis.bat
@@ -23,6 +23,5 @@ REM Execute SIS with any optional JAR that the user may put 
in the 'lib' directo
 java --module-path 
"%BASE_DIR%\lib;%BASE_DIR%\lib\app\org.apache.sis.console.jar"^
      -Djava.util.logging.config.class=org.apache.sis.util.logging.Initializer^
      -Djava.util.logging.config.file="%BASE_DIR%\conf\logging.properties"^
-     -Dderby.stream.error.file="%BASE_DIR%\log\derby.log"^
      --module org.apache.sis.console/org.apache.sis.console.Command^
      %SIS_OPTS% %*
diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sisfx 
b/optional/src/org.apache.sis.gui/bundle/bin/sisfx
index c33c5a27c2..a5ed59ff7e 100755
--- a/optional/src/org.apache.sis.gui/bundle/bin/sisfx
+++ b/optional/src/org.apache.sis.gui/bundle/bin/sisfx
@@ -93,7 +93,6 @@ java -splash:"$BASE_DIR/lib/logo.jpg" \
      --module-path 
"$PATH_TO_FX:$BASE_DIR/lib:$BASE_DIR/lib/app/org.apache.sis.gui.jar" \
      
-Djava.util.logging.config.class="org.apache.sis.util.logging.Initializer" \
      -Djava.util.logging.config.file="$BASE_DIR/conf/logging.properties" \
-     -Dderby.stream.error.file="$BASE_DIR/log/derby.log" \
      $ADD_OPTIONAL_MODULES \
      --module org.apache.sis.gui/org.apache.sis.gui.DataViewer \
      $SIS_OPTS "$@"
diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sisfx.bat 
b/optional/src/org.apache.sis.gui/bundle/bin/sisfx.bat
index eaeca53264..39b00a9ad1 100644
--- a/optional/src/org.apache.sis.gui/bundle/bin/sisfx.bat
+++ b/optional/src/org.apache.sis.gui/bundle/bin/sisfx.bat
@@ -30,6 +30,5 @@ java -splash:"%BASE_DIR%\lib\logo.jpg"^
  --module-path 
"%PATH_TO_FX%;%BASE_DIR%\lib;%BASE_DIR%\lib\app\org.apache.sis.gui.jar"^
  -Djava.util.logging.config.class=org.apache.sis.util.logging.Initializer^
  -Djava.util.logging.config.file="%BASE_DIR%\conf\logging.properties"^
- -Dderby.stream.error.file="%BASE_DIR%\log\derby.log"^
  --module org.apache.sis.gui/org.apache.sis.gui.DataViewer^
  %SIS_OPTS%
diff --git a/optional/src/org.apache.sis.gui/bundle/lib/README 
b/optional/src/org.apache.sis.gui/bundle/lib/README
index 5eec4daeb4..6b66eff7a5 100644
--- a/optional/src/org.apache.sis.gui/bundle/lib/README
+++ b/optional/src/org.apache.sis.gui/bundle/lib/README
@@ -3,7 +3,7 @@ together with the following dependencies:
 
   - JAXB API
   - JAXB implementation  (optional)
-  - Derby database       (optional)
+  - HSQL database        (optional)
 
 The following dependencies are not included
 but will be used if they are added by users:
diff --git a/optional/src/org.apache.sis.gui/bundle/log/README 
b/optional/src/org.apache.sis.gui/bundle/log/README
index a1966eb900..128cc56522 100644
--- a/optional/src/org.apache.sis.gui/bundle/log/README
+++ b/optional/src/org.apache.sis.gui/bundle/log/README
@@ -1,3 +1,2 @@
 This directory contains log messages produced by the system
-(Java + SIS + other applications), and a separated file for
-logs from Derby database driver.
+(Java + SIS + other applications).
diff --git 
a/optional/src/org.apache.sis.referencing.database/main/module-info.java 
b/optional/src/org.apache.sis.referencing.database/main/module-info.java
index cb55c1261a..8eb9e3b917 100644
--- a/optional/src/org.apache.sis.referencing.database/main/module-info.java
+++ b/optional/src/org.apache.sis.referencing.database/main/module-info.java
@@ -16,7 +16,7 @@
  */
 
 /**
- * Embedded EPSG geodetic dataset.
+ * Embedded <abbr>EPSG</abbr> geodetic dataset.
  * This module contains the data of the {@code 
org.apache.sis.referencing.epsg} module,
  * but in a form that does not require the installation of a local database.
  *
@@ -28,12 +28,12 @@
  * see <a href="https://sis.apache.org/epsg.html";>How to use EPSG geodetic 
dataset</a> on the <abbr>SIS</abbr> web site.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
  * @since   0.7
  */
 module org.apache.sis.referencing.database {
     requires transitive org.apache.sis.referencing;
-    requires            org.apache.derby.tools;
+    requires            org.hsqldb;
 
     exports org.apache.sis.resources.embedded;
 
diff --git 
a/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java
 
b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java
index 79524923b1..51b9becd2a 100644
--- 
a/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java
+++ 
b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java
@@ -23,7 +23,7 @@ import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.IOException;
 import javax.sql.DataSource;
-import org.apache.derby.jdbc.EmbeddedDataSource;
+import org.hsqldb.jdbc.JDBCDataSource;
 import org.apache.sis.util.internal.shared.MetadataServices;
 import org.apache.sis.metadata.sql.internal.shared.Initializer;
 import org.apache.sis.setup.InstallationResources;
@@ -36,7 +36,7 @@ import org.apache.sis.util.resources.Errors;
  * which should be accepted by users before the EPSG dataset can be installed.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
  * @since   0.8
  *
  * @see <a href="https://epsg.org/";>https://epsg.org/</a>
@@ -44,9 +44,9 @@ import org.apache.sis.util.resources.Errors;
 public class EmbeddedResources extends InstallationResources {
     /**
      * The root directory of data embedded in the <abbr>JAR</abbr> file.
-     * It must be an invalid package name, because otherwise the Java Platform 
Module System (JPMS) enforces
-     * encapsulation in the same way as non-exported packages, which makes the 
database inaccessible to Derby.
-     * This naming trick is part of <abbr>JPMS</abbr> specification, so it 
should be reliable.
+     * It must be an invalid package name, because otherwise the Java Module 
System enforces
+     * encapsulation in the same way as non-exported packages, which makes 
files inaccessible.
+     * This naming trick is part of Java Module specification, so it should be 
reliable.
      */
     static final String DIRECTORY = "SIS-DATA";
 
@@ -143,9 +143,9 @@ public class EmbeddedResources extends 
InstallationResources {
              * be the case when using a local build.
              */
             if (dataSource == null && 
EmbeddedResources.class.getResourceAsStream("LICENSE.txt") != null) {
-                final var ds = new EmbeddedDataSource();
-                ds.setDataSourceName(Initializer.DATABASE);
-                ds.setDatabaseName("classpath:" + DIRECTORY + "/Databases/" + 
Initializer.DATABASE);
+                final var ds = new JDBCDataSource();
+                ds.setDatabaseName(Initializer.DATABASE);
+                ds.setURL("jdbc:hsqldb:res:" + DIRECTORY + "/Databases/" + 
Initializer.DATABASE);
                 dataSource = ds;
             }
             return dataSource;
diff --git 
a/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java
 
b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java
index 893d4b032d..431316b4a7 100644
--- 
a/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java
+++ 
b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java
@@ -17,7 +17,7 @@
 
 /**
  * Provides data, including the non-free <abbr>EPSG</abbr> geodetic dataset, 
in a single read-only <abbr>JAR</abbr> file.
- * This module contains a copy of the <abbr>EPSG</abbr> geodetic dataset in an 
embedded Apache Derby database.
+ * This module contains a copy of the <abbr>EPSG</abbr> geodetic dataset in an 
embedded <abbr>HSQL</abbr> database.
  * Having this module on the module-path avoid the need to set the {@code 
SIS_DATA} environment variable
  * for using the Coordinate Reference Systems (<abbr>CRS</abbr>) and 
Coordinate Operations defined by <abbr>EPSG</abbr>.
  *
@@ -29,7 +29,7 @@
  * see <a href="https://sis.apache.org/epsg.html";>How to use EPSG geodetic 
dataset</a> on the <abbr>SIS</abbr> web site.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
  * @since   0.8
  */
 package org.apache.sis.resources.embedded;
diff --git 
a/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.java
 
b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.java
index df17faef0e..e5948f847e 100644
--- 
a/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.java
+++ 
b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.java
@@ -127,7 +127,7 @@ public final class EmbeddedResourcesTest {
         final DataSource ds = Initializer.getDataSource();
         assertNotNull(ds, "Cannot find the data source.");
         try (Connection c = ds.getConnection()) {
-            assertEquals("jdbc:derby:classpath:" + EmbeddedResources.DIRECTORY 
+ "/Databases/" + Initializer.DATABASE, c.getMetaData().getURL(), "URL");
+            assertEquals("jdbc:hsqldb:res:" + EmbeddedResources.DIRECTORY + 
"/Databases/" + Initializer.DATABASE, c.getMetaData().getURL(), "URL");
             try (Statement s = c.createStatement()) {
                 try (ResultSet r = s.executeQuery("SELECT COORD_REF_SYS_NAME 
FROM EPSG.\"Coordinate Reference System\" WHERE COORD_REF_SYS_CODE = 4326")) {
                     assertTrue(r.next(), "ResultSet.next()");
diff --git 
a/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java
 
b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java
index 046c390466..09166f172b 100644
--- 
a/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java
+++ 
b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java
@@ -16,25 +16,22 @@
  */
 package org.apache.sis.resources.embedded;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.URISyntaxException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.sql.CallableStatement;
 import java.sql.Connection;
-import java.sql.ResultSet;
 import java.sql.SQLException;
-import org.apache.derby.jdbc.EmbeddedDataSource;
+import java.sql.Statement;
+import org.hsqldb.jdbc.JDBCDataSource;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.apache.sis.metadata.MetadataStandard;
 import org.apache.sis.metadata.sql.MetadataSource;
 import org.apache.sis.metadata.sql.MetadataStoreException;
 import org.apache.sis.metadata.sql.internal.shared.Initializer;
-import org.apache.sis.metadata.sql.internal.shared.LocalDataSource;
 import org.apache.sis.referencing.factory.sql.EPSGFactory;
 import org.apache.sis.referencing.factory.sql.epsg.ScriptProvider;
 
@@ -69,14 +66,14 @@ final class Generator extends ScriptProvider {
      * The connection <abbr>URL</abbr> references the following directory in 
the compilation output directory:
      * <code>{@value EmbeddedResources#DIRECTORY}/Databases/{@value 
Initializer#DATABASE}</code>
      */
-    private final EmbeddedDataSource dataSource;
+    private final JDBCDataSource dataSource;
 
     /**
      * Creates a new database generator.
      */
     Generator() throws URISyntaxException, IOException {
-        dataSource = new EmbeddedDataSource();
-        dataSource.setDataSourceName(Initializer.DATABASE);
+        dataSource = new JDBCDataSource();
+        dataSource.setDatabaseName(Initializer.DATABASE);
         classesDirectory = directoryOf(EmbeddedResources.class);
         Path target = classesDirectory;
         do target = target.getParent();     // Move to the root directory of 
classes.
@@ -90,9 +87,8 @@ final class Generator extends ScriptProvider {
             target = Files.createDirectory(target);
             target = Files.createDirectory(target.resolve("Databases"));
             sourceEPSG = directoryOf(ScriptProvider.class);
-            dataSource.setCreateDatabase("create");
         }
-        
dataSource.setDatabaseName(target.resolve(Initializer.DATABASE).toString());
+        dataSource.setURL("jdbc:hsqldb:file:" + 
target.resolve(Initializer.DATABASE).toString());
     }
 
     /**
@@ -124,7 +120,6 @@ final class Generator extends ScriptProvider {
             copyLicenseFiles();
             createMetadata();
             createEPSG();
-            compress();
             shutdown();
         }
     }
@@ -192,47 +187,13 @@ final class Generator extends ScriptProvider {
     }
 
     /**
-     * Compresses all tables in all schema. Compression can save space if 
there was many update
-     * or delete operations in the database. In the case of the database 
generated by this class,
-     * the benefit is very small because the database is fresh. But it is 
still non-zero.
-     */
-    private void compress() throws SQLException {
-        try (Connection c = dataSource.getConnection()) {
-            final var tables = new ArrayList<String>(80);  // As 
(schema,table) pairs.
-            try (ResultSet r = c.getMetaData().getTables(null, null, null, 
null)) {
-                while (r.next()) {
-                    final String schema = r.getString("TABLE_SCHEM");
-                    if (!schema.startsWith("SYS")) {
-                        tables.add(schema);
-                        tables.add(r.getString("TABLE_NAME"));
-                    }
-                }
-            }
-            try (CallableStatement cs = c.prepareCall("CALL 
SYSCS_UTIL.SYSCS_COMPRESS_TABLE(?, ?, ?)")) {
-                for (int i=0; i<tables.size();) {
-                    cs.setString(1, tables.get(i++));       // Schema name.
-                    cs.setString(2, tables.get(i++));       // Table name.
-                    cs.setShort (3, (short) 1);
-                    cs.execute();
-                }
-            }
-        }
-    }
-
-    /**
-     * Shutdowns the Derby database.
+     * Shutdowns the database.
      */
     private void shutdown() throws SQLException {
-        dataSource.setCreateDatabase("no");
-        dataSource.setShutdownDatabase("shutdown");
-        try {
-            dataSource.getConnection().close();
-        } catch (SQLException e) {
-            if (LocalDataSource.isSuccessfulShutdown(e)) {
-                return;
-            }
-            throw e;
+        try (Connection c = dataSource.getConnection();
+             Statement stmt = c.createStatement())
+        {
+            stmt.execute("SHUTDOWN COMPACT");
         }
-        throw new SQLException("Shutdown has not been completed.");
     }
 }
diff --git a/optional/src/org.apache.sis.referencing.epsg/main/module-info.java 
b/optional/src/org.apache.sis.referencing.epsg/main/module-info.java
index a6ec05daf8..8f4f4a6abb 100644
--- a/optional/src/org.apache.sis.referencing.epsg/main/module-info.java
+++ b/optional/src/org.apache.sis.referencing.epsg/main/module-info.java
@@ -15,9 +15,9 @@
  */
 
 /**
- * SQL scripts for EPSG geodetic data set installation.
+ * <abbr>SQL</abbr> scripts for <abbr>EPSG</abbr> geodetic data set 
installation.
  * This module provides the <abbr>EPSG</abbr> data of the {@code 
org.apache.sis.referencing.database} module,
- * but in a form that allows installation on <abbr>SQL</abbr> databases other 
than Apache Derby.
+ * but in a form that allows installation in different <abbr>SQL</abbr> 
databases.
  *
  * <h2>Licensing</h2>
  * EPSG is maintained by the <a href="https://www.iogp.org/";>International 
Association of Oil and Gas Producers</a>
diff --git 
a/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
 
b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
index 2cc9218469..66ff572bc4 100644
--- 
a/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
+++ 
b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
@@ -60,9 +60,7 @@ export NON_FREE_DIR=$PWD
 
 cd _<path to SIS project directory>_
 gradle clean test jar
-export 
CLASSPATH=~/.m2/repository/org/apache/derby/derby/10.15.2.0/derby-10.15.2.0.jar
-export 
CLASSPATH=~/.m2/repository/org/apache/derby/derbyshared/10.15.2.0/derbyshared-10.15.2.0.jar:$CLASSPATH
-export 
CLASSPATH=~/.m2/repository/org/apache/derby/derbytools/10.15.2.0/derbytools-10.15.2.0.jar:$CLASSPATH
+export CLASSPATH=~/.m2/repository/org/hsqldb/hsqldb/2.7.4/hsqldb-2.7.4.jar
 export 
CLASSPATH=~/.m2/repository/org/postgresql/postgresql/42.7.7/postgresql-42.7.7.jar:$CLASSPATH
 export 
CLASSPATH=~/.m2/repository/javax/measure/unit-api/2.1.3/unit-api-2.1.3.jar:$CLASSPATH
 export 
CLASSPATH=~/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.4/jakarta.xml.bind-api-4.0.4.jar:$CLASSPATH

Reply via email to