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

desruisseaux 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 b0791bfff2 Drop support of the `$SIS_DATA/Databases/ExternalSources` 
directory. This feature was used mostly for testing purposes, so this change 
has probably no incidence on users. In the unlikely case where this feature was 
used by someone in production, it would probably be broken anyway because this 
feature had an implicit execution of scripts that are impacted by the EPSG 
upgrade.
b0791bfff2 is described below

commit b0791bfff2bced9bd2b82ddc92e4f7484838eaa4
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Aug 19 19:21:44 2025 +0200

    Drop support of the `$SIS_DATA/Databases/ExternalSources` directory.
    This feature was used mostly for testing purposes, so this change has 
probably no incidence on users.
    In the unlikely case where this feature was used by someone in production, 
it would probably be broken
    anyway because this feature had an implicit execution of scripts that are 
impacted by the EPSG upgrade.
    
    https://issues.apache.org/jira/browse/SIS-611
---
 .../referencing/factory/sql/EPSGDataAccess.java    |   6 +-
 .../sis/referencing/factory/sql/EPSGFactory.java   |  32 ++--
 .../sis/referencing/factory/sql/EPSGInstaller.java |  18 +-
 .../factory/sql/InstallationScriptProvider.java    | 198 ++++-----------------
 .../sis/referencing/factory/sql/TableInfo.java     |   4 +-
 .../referencing/factory/sql/EPSGInstallerTest.java |  20 +--
 .../factory/sql/EPSGScriptProvider.java            | 113 ++++++++++++
 .../apache/sis/setup/InstallationResources.java    |   2 +-
 .../main/org/apache/sis/util/resources/Errors.java |   7 +-
 .../apache/sis/util/resources/Errors.properties    |   1 -
 .../apache/sis/util/resources/Errors_fr.properties |   1 -
 .../sis/referencing/factory/sql/epsg/.gitignore    |   5 +-
 .../sis/referencing/factory/sql/epsg/Finish.sql    |   0
 .../sis/referencing/factory/sql/epsg/Prepare.sql   |   0
 .../factory/sql/epsg/ScriptProvider.java           |  32 ++--
 15 files changed, 203 insertions(+), 236 deletions(-)

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 c5dff9eb64..30bf3d492f 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
@@ -1597,7 +1597,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                 final FactoryCall<CRSFactory, CoordinateReferenceSystem> 
constructor;
                 /*
                  * The following switch statement should have a case for all 
"CRS Kind" values enumerated
-                 * in the "EPSG_Prepare.sql" file, except that the values in 
this Java code are in lower cases.
+                 * in the `Prepare.sql` file, except that the values in this 
Java code are in lower cases.
                  */
                 switch (type.toLowerCase(Locale.US)) {
                     /* 
──────────────────────────────────────────────────────────────────────
@@ -1919,7 +1919,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                 final FactoryCall<DatumFactory, ? extends Datum> constructor;
                 /*
                  * The following switch statement should have a case for all 
"Datum Kind" values enumerated
-                 * in the "EPSG_Prepare.sql" file, except that the values in 
this Java code are in lower cases.
+                 * in the `Prepare.sql` file, except that the values in this 
Java code are in lower cases.
                  */
                 switch (type.toLowerCase(Locale.US)) {
                     case "dynamic geodetic":
@@ -2507,7 +2507,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                         "Coordinate System", epsg, name, null, null, null, 
remarks, deprecated);
                 /*
                  * The following switch statement should have a case for all 
"CS Kind" values enumerated
-                 * in the "EPSG_Prepare.sql" file, except that the values in 
this Java code are in lower cases.
+                 * in the `Prepare.sql` file, except that the values in this 
Java code are in lower cases.
                  */
                 final CSFactory csFactory = owner.csFactory;
                 CoordinateSystem cs = null;
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 4c8dd3ac1b..d2339bc03e 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
@@ -321,7 +321,7 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
 
     /**
      * Creates the EPSG schema in the database and populates the tables with 
geodetic definitions.
-     * This method is invoked automatically when {@link #newDataAccess()} 
detects that the EPSG dataset is not installed.
+     * This method is invoked automatically when {@link #newDataAccess()} 
detects that the <abbr>EPSG</abbr> geodetic dataset is not installed.
      * Users can also invoke this method explicitly if they wish to force the 
dataset installation.
      *
      * <p>This method uses the following properties from the map specified at
@@ -332,33 +332,27 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
      *     a {@link String} giving the name of the database catalog where to 
create the EPSG schema.
      *     If non-null, that catalog shall exist prior this method call (this 
method does not create any catalog).
      *     If no catalog is specified or if the catalog is an empty string,
-     *     then the EPSG schema will be created without catalog.
-     *     If the database does not {@linkplain 
DatabaseMetaData#supportsCatalogsInTableDefinitions() support
-     *     catalogs in table definitions} or in {@linkplain 
DatabaseMetaData#supportsCatalogsInDataManipulation()
-     *     data manipulation}, then this property is ignored.</li>
+     *     then the EPSG schema will be created without catalog. If the 
database does not
+     *     {@linkplain DatabaseMetaData#supportsCatalogsInTableDefinitions() 
support catalogs in table definitions} or in
+     *     {@linkplain DatabaseMetaData#supportsCatalogsInDataManipulation() 
data manipulation}, then this property is ignored.</li>
      *
      *   <li><b>{@code schema}:</b><br>
-     *     a {@link String} giving the name of the database schema where to 
create the EPSG tables.
-     *     That schema shall <strong>not</strong> exist prior this method call;
-     *     the schema will be created by this {@code install(…)} method.
+     *     a {@link String} giving the name of the database schema where to 
create the <abbr>EPSG</abbr> tables.
+     *     That schema shall <strong>not</strong> exist prior this method call.
+     *     The schema will be created by this {@code install(…)} method.
      *     If the schema is an empty string, then the tables will be created 
without schema.
-     *     If no schema is specified, then the default schema is {@code 
"EPSG"}.
-     *     If the database does not {@linkplain 
DatabaseMetaData#supportsSchemasInTableDefinitions() support
-     *     schemas in table definitions} or in {@linkplain 
DatabaseMetaData#supportsSchemasInDataManipulation()
-     *     data manipulation}, then this property is ignored.</li>
+     *     If no schema is specified, then the default schema is {@code 
"EPSG"}. If the database does not
+     *     {@linkplain DatabaseMetaData#supportsSchemasInTableDefinitions() 
support schemas in table definitions} or in
+     *     {@linkplain DatabaseMetaData#supportsSchemasInDataManipulation() 
data manipulation}, then this property is ignored.</li>
      *
      *   <li><b>{@code scriptProvider}:</b><br>
-     *     an {@link InstallationScriptProvider} giving the SQL scripts to 
execute for creating the EPSG database.
+     *     an {@link InstallationScriptProvider} giving the <abbr>SQL</abbr> 
scripts to execute for creating the EPSG schema.
      *     If no provider is specified, then this method searches on the 
module path (with {@link java.util.ServiceLoader})
-     *     for user-provided implementations of {@code 
InstallationScriptProvider}.
-     *     If no user-specified provider is found, then this method will 
search for
-     *     {@code "*Tables*.sql"}, {@code "*Data*.sql"} and {@code 
"*FKeys*.sql"} files in the
-     *     {@code $SIS_DATA/Databases/ExternalSources/EPSG} directory where 
{@code *} stands for any characters
-     *     provided that there is no ambiguity.</li>
+     *     for user-provided implementations of {@code 
InstallationScriptProvider}.</li>
      * </ul>
      *
      * <h4>Legal constraint</h4>
-     * The EPSG dataset cannot be distributed with Apache SIS for licensing 
reasons.
+     * The <abbr>EPSG</abbr> dataset cannot be distributed with Apache SIS for 
licensing reasons.
      * Users need to either install the dataset manually (for example with the 
help of this method),
      * or add on the module path a separated bundle such as the {@code 
org.apache.sis.referencing.epsg} module.
      * See <a href="https://sis.apache.org/epsg.html";>How to use EPSG geodetic 
dataset</a> for more information.
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 28afba7e4b..1b4deea485 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
@@ -51,6 +51,8 @@ final class EPSGInstaller extends ScriptRunner {
 
     /**
      * Whether to apply the replacements in the {@link 
#identifierReplacements} map.
+     * Used for temporarily disabling the replacements during the execution of 
the
+     * {@code Prepare.sql} script, which defines the enumerations.
      */
     private boolean applyReplacements;
 
@@ -149,11 +151,12 @@ final class EPSGInstaller extends ScriptRunner {
                 Messages.Keys.CreatingSchema_2,
                 Constants.EPSG,
                 SQLUtilities.getSimplifiedURL(getConnection().getMetaData())));
+
+        int numRows = 0;    // For logging purpose only.
         final String[] scripts = 
scriptProvider.getResourceNames(Constants.EPSG);
-        int numRows = 0;
         for (int i=0; i<scripts.length; i++) {
             final String script = scripts[i];
-            applyReplacements = !(identifierReplacements.isEmpty() || 
InstallationScriptProvider.PREPARE.equals(script));
+            applyReplacements = (i != 0) && !identifierReplacements.isEmpty();
             try (BufferedReader in = scriptProvider.openScript(Constants.EPSG, 
i)) {
                 numRows += run(script, in);
             }
@@ -175,9 +178,6 @@ final class EPSGInstaller extends ScriptRunner {
      *   <li>A provider from a publicly supported dependency such as {@code 
sis-epsg.jar} or {@code sis-embedded.jar}.
      *       Users have to put one of those dependencies in the module path 
themselves. This action is interpreted as
      *       an acceptance of EPSG terms of use, so no license agreement 
window will popup.</li>
-     *   <li>A provider using the SQL scripts in the {@code 
$SIS_DATA/Databases/ExternalSources/EPSG} directory.
-     *       Users have to put those scripts in that directory manually. This 
action is interpreted as an
-     *       acceptance of EPSG terms of use, so no license agreement window 
will popup.</li>
      *   <li>A provider offering users to automatically download the data. 
Those providers are defined by
      *       {@code org.apache.sis.console} and {@code org.apache.sis.gui} 
modules.
      *       Users must accept EPSG terms of use before the database can be 
installed.
@@ -197,14 +197,12 @@ final class EPSGInstaller extends ScriptRunner {
             }
         }
         /*
-         * If we did not found a provider ready to use such as "sis-epsg.jar" 
or "sis-embedded.jar",
+         * If we did not found a provider ready to use such as `sis-epsg.jar` 
or `sis-embedded.jar`,
          * we may fallback on a provider offering to download the data (those 
fallbacks are provided
          * by `org.apache.sis.console` and `org.apache.sis.gui` modules). 
Those fallbacks will ask to
-         * the user if (s)he accepts EPSG terms of use. But before to use 
those fallbacks, check if the
-         * data have not been downloaded manually in the 
"$SIS_DATA/Databases/ExternalSources/EPSG" directory.
+         * the users if they accept the EPSG Terms of Use.
          */
-        final var manual = new InstallationScriptProvider.Default(locale);
-        return manual.getAuthorities().isEmpty() ? fallback : manual;
+        return fallback;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java
index 096efdad13..d98e95db97 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java
@@ -17,9 +17,7 @@
 package org.apache.sis.referencing.factory.sql;
 
 import java.util.Set;
-import java.util.Locale;
 import java.util.Objects;
-import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.sql.Connection;
 import java.io.BufferedReader;
@@ -29,24 +27,17 @@ import java.io.InputStreamReader;
 import java.io.IOException;
 import java.io.FileNotFoundException;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.nio.file.NoSuchFileException;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.setup.InstallationResources;
 import org.apache.sis.referencing.internal.Resources;
-import org.apache.sis.system.Fallback;
-import org.apache.sis.system.DataDirectory;
-import org.apache.sis.util.privy.CollectionsExt;
 import org.apache.sis.util.privy.Constants;
-import org.apache.sis.pending.jdk.JDK22;
 
 
 /**
- * Provides SQL scripts needed for creating a local copy of a dataset. This 
class allows Apache <abbr>SIS</abbr> users
- * to bundle the <abbr>EPSG</abbr> geodetic datasets in their own product for 
automatic installation when first needed.
+ * Provides the <abbr>SQL</abbr> scripts needed for creating a local copy of a 
geodetic dataset.
+ * This is used mostly for automatic installation of the <abbr>EPSG</abbr> 
dataset, but could also be used for other registries.
  * Implementations of this class are discovered automatically by {@link 
EPSGFactory} if they are declared in the
  * {@code module-info.class} file as providers of the {@code 
org.apache.sis.setup.InstallationResources} service.
  *
@@ -74,7 +65,10 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
      * This is an Apache <abbr>SIS</abbr> build-in script for replacing the 
{@code VARCHAR} type of some columns
      * by enumeration types, in order to constraint the values to the codes 
recognized by {@link EPSGDataAccess}.
      * Those enumerations are not mandatory for allowing {@link EPSGFactory} 
to work, but improve data integrity.
+     *
+     * @deprecated Ignored since the upgrade to version 10+ of 
<abbr>EPSG</abbr> because too dependent of the database schema.
      */
+    @Deprecated(since = "1.5", forRemoval = true)
     protected static final String PREPARE = "Prepare";
 
     /**
@@ -82,7 +76,10 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
      * This is an Apache <abbr>SIS</abbr> build-in script for creating indexes 
or performing other manipulations
      * that help <abbr>SIS</abbr> to use the dataset. Those indexes are not 
mandatory for allowing
      * {@link EPSGFactory} to work, but improve performances.
+     *
+     * @deprecated Ignored since the upgrade to version 10+ of 
<abbr>EPSG</abbr> because too dependent of the database schema.
      */
+    @Deprecated(since = "1.5", forRemoval = true)
     protected static final String FINISH = "Finish";
 
     /**
@@ -96,37 +93,37 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
     private final String[] resources;
 
     /**
-     * Creates a new provider which will read script files of the given names 
in that order.
+     * Creates a new provider which will read script files of the given names 
in the given order.
      * The given names are often filenames, but not necessarily
      * (it is okay to use those names only as labels).
      *
      * <table class="sis">
-     *   <caption>Typical argument values</caption>
+     *   <caption>Example of argument values</caption>
      *   <tr>
      *     <th>Authority</th>
-     *     <th class="sep">Argument values</th>
+     *     <th class="sep">Resources</th>
      *   </tr><tr>
      *     <td>{@code EPSG}</td>
      *     <td class="sep"><code>
-     *       {{@linkplain #PREPARE}, "Tables.sql", "Data.sql", "FKeys.sql", 
{@linkplain #FINISH}}
+     *       {"Tables.sql", "Data.sql", "FKeys.sql", "Indexes.sql"}
      *     </code></td>
      *   </tr>
      * </table>
      *
      * @param  authority  the authority (typically {@code "EPSG"}), or {@code 
null} if not available.
-     * @param  resources  names of the SQL scripts to read.
+     * @param  resources  names of the <abbr>SQL</abbr> scripts to read 
(typically filenames).
      *
      * @see #getResourceNames(String)
      * @see #openStream(String)
      */
     protected InstallationScriptProvider(final String authority, final 
String... resources) {
         this.resources = Objects.requireNonNull(resources);
-        authorities = CollectionsExt.singletonOrEmpty(authority);
+        authorities = (authority != null) ? Set.of(authority) : Set.of();
     }
 
     /**
-     * Returns the identifiers of the dataset installed by the SQL scripts.
-     * The values currently recognized by SIS are:
+     * Returns the identifiers of the dataset installed by the 
<abbr>SQL</abbr> scripts.
+     * The values currently recognized by <abbr>SIS</abbr> are:
      *
      * <ul>
      *   <li>{@code "EPSG"} for the <abbr>EPSG</abbr> geodetic dataset.</li>
@@ -174,25 +171,10 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
      * The script may be read, for example, from a local file or from a 
resource in a <abbr>JAR</abbr> file.
      * The returned {@link BufferedReader} instance shall be closed by the 
caller.
      *
-     * <h4><abbr>EPSG</abbr> case</h4>
-     * In the case of the <abbr>EPSG</abbr> geodetic dataset, this method 
should return the following scripts
-     * (replace {@code <product>} by the target database such as {@code 
PostgreSQL}), in the same order.
-     * The first and last files are provided by Apache <abbr>SIS</abbr>.
-     * All other files can be downloaded from <a 
href="https://epsg.org/";>https://epsg.org/</a>.
-     *
-     * <ol start="0">
-     *   <li>Content of {@link #PREPARE}, an optional data definition script 
that define the enumerations expected by {@link EPSGDataAccess}.</li>
-     *   <li>Content of {@code "<product>_Tables_Script.sql"}, a data 
definition script that create empty tables.</li>
-     *   <li>Content of {@code "<product>_Data_Script.sql"}, a data 
manipulation script that populate the tables.</li>
-     *   <li>Content of {@code "<product>_FKeys_Script.sql"}, a data 
definition script that create foreigner key constraints.</li>
-     *   <li>Content of {@link #FINISH}, an optional data definition and data 
control script that create indexes and set permissions.</li>
-     * </ol>
-     *
      * <h4>Default implementation</h4>
-     * The default implementation delegates to {@link #openStream(String)},
-     * except for {@link #PREPARE} and {@link #FINISH} which are Apache 
<abbr>SIS</abbr> build-in scripts.
-     * The input stream returned by {@code openStream(…)} is assumed encoded 
in <abbr>UTF</abbr>-8 and is
-     * wrapped in a {@link LineNumberReader}.
+     * The default implementation delegates to {@link #openStream(String)}.
+     * The input stream returned by {@code openStream(…)} is assumed encoded
+     * in <abbr>UTF</abbr>-8 and is wrapped in a {@link LineNumberReader}.
      *
      * @param  authority  the value given at construction time (e.g. {@code 
"EPSG"}).
      * @param  resource   index of the <abbr>SQL</abbr> script to read, from 0 
inclusive to
@@ -200,7 +182,7 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
      * @return a reader for the content of <abbr>SQL</abbr> script to execute.
      * @throws IllegalArgumentException if the given {@code authority} 
argument is not the expected value.
      * @throws IndexOutOfBoundsException if the given {@code resource} 
argument is out of bounds.
-     * @throws FileNotFoundException if the SQL script of the given name has 
not been found.
+     * @throws FileNotFoundException if the <abbr>SQL</abbr> script of the 
given name has not been found.
      * @throws IOException if an error occurred while creating the reader.
      */
     @Override
@@ -210,35 +192,29 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
             throw new 
IllegalStateException(Resources.format(Resources.Keys.UnknownAuthority_1, 
authority));
         }
         String name = resources[resource];
-        InputStream in;
         NoSuchFileException cause = null;
-        if (PREPARE.equals(name) || FINISH.equals(name)) {
-            name = authority + '_' + name + ".sql";
-            in = InstallationScriptProvider.class.getResourceAsStream(name);
-        } else try {
-            in = openStream(name);
+        try {
+            final InputStream in = openStream(name);
+            if (in != null) {
+                return new LineNumberReader(new InputStreamReader(in, 
StandardCharsets.UTF_8));
+            }
         } catch (NoSuchFileException e) {
             cause = e;
-            in = null;
-        }
-        if (in == null) {
-            var e = new 
FileNotFoundException(Errors.format(Errors.Keys.FileNotFound_1, name));
-            e.initCause(cause);
-            throw e;
         }
-        return new LineNumberReader(new InputStreamReader(in, 
StandardCharsets.UTF_8));
+        var e = new 
FileNotFoundException(Errors.format(Errors.Keys.FileNotFound_1, name));
+        e.initCause(cause);
+        throw e;
     }
 
     /**
-     * Opens the input stream for the SQL script of the given name.
-     * This method is invoked by the default implementation of {@link 
#openScript(String, int)}
-     * for all scripts except {@link #PREPARE} and {@link #FINISH}.
+     * Opens the input stream for the <abbr>SQL</abbr> script of the given 
name.
+     * This method is invoked by the default implementation of {@link 
#openScript(String, int)}.
      * The returned input stream does not need to be buffered.
      *
      * <h4>Example 1</h4>
-     * If this {@code InstallationScriptProvider} instance gets the SQL 
scripts from files in a well-known directory
-     * and if the names given at {@linkplain 
#InstallationScriptProvider(String, String...) construction time} are the
-     * filenames in that directory, then this method can be implemented as 
below:
+     * If this {@code InstallationScriptProvider} instance gets the 
<abbr>SQL</abbr> scripts from files in a well-known directory
+     * and if the names given at {@linkplain 
#InstallationScriptProvider(String, String...) construction time} are filenames
+     * in that directory, then this method can be implemented as below:
      *
      * {@snippet lang="java" :
      *      protected InputStream openStream(String name) throws IOException {
@@ -269,112 +245,4 @@ public abstract class InstallationScriptProvider extends 
InstallationResources {
     static void log(final LogRecord record) {
         Logging.completeAndLog(EPSGDataAccess.LOGGER, EPSGFactory.class, 
"install", record);
     }
-
-
-
-
-    /**
-     * The default implementation which uses the scripts in the {@code 
$SIS_DATA/Databases/ExternalSources/EPSG}
-     * directory, if present. This class expects the files to have those exact 
names where {@code *} stands
-     * for any characters provided that there is no ambiguity:
-     *
-     * <ul>
-     *   <li>{@code *Tables*.sql}</li>
-     *   <li>{@code *Data*.sql}</li>
-     *   <li>{@code *FKeys*.sql}</li>
-     * </ul>
-     *
-     * @author  Martin Desruisseaux (Geomatys)
-     */
-    @Fallback
-    static final class Default extends InstallationScriptProvider {
-        /**
-         * The directory containing the scripts, or {@code null} if it does 
not exist.
-         */
-        private final Path directory;
-
-        /**
-         * Index of the first real file in the array given to the constructor.
-         * We set the value to 1 for skipping the {@code PREPARE} pseudo-file.
-         */
-        private static final int FIRST_FILE = 1;
-
-        /**
-         * Creates a default provider.
-         *
-         * @param locale  the locale for warning messages, if any.
-         */
-        Default(final Locale locale) throws IOException {
-            super(Constants.EPSG, PREPARE, "Tables", "Data", "FKeys", FINISH);
-            final String[] resources = super.resources;
-            final String[] found = new String[resources.length - (FIRST_FILE + 
1)];   // +1 is for omitting `FINISH`.
-            @SuppressWarnings("LocalVariableHidesMemberVariable")
-            Path directory = DataDirectory.DATABASES.getDirectory();
-            if (directory != null && Files.isDirectory(directory = 
JDK22.resolve(directory, "ExternalSources", Constants.EPSG))) {
-                try (DirectoryStream<Path> content = 
Files.newDirectoryStream(directory, "*.sql")) {
-                    for (final Path path : content) {
-                        final String name = path.getFileName().toString();
-                        for (int i=0; i<found.length; i++) {
-                            final String part = resources[FIRST_FILE + i];
-                            if (name.contains(part)) {
-                                if (found[i] == null) {
-                                    found[i] = name;
-                                } else {
-                                    directory = null;
-                                    
log(Errors.forLocale(locale).createLogRecord(Level.WARNING,
-                                            
Errors.Keys.DuplicatedFileReference_1, part));
-                                }
-                            }
-                        }
-                    }
-                }
-            } else {
-                directory = null;       // Does not exist or is not a 
directory.
-            }
-            this.directory = directory;
-            for (int i=0; i<found.length; i++) {
-                String file = found[i];
-                if (file == null) {
-                    // File not found. Create a default name which will appear 
in the exception to be thrown.
-                    file = resources[FIRST_FILE + i] + ".sql";
-                }
-                resources[FIRST_FILE + i] = file;
-            }
-        }
-
-        /**
-         * Returns {@code "EPSG"} if the scripts exist in the {@code 
ExternalSources/EPSG} subdirectory,
-         * or an empty set otherwise.
-         *
-         * @return {@code "EPSG"} if the SQL scripts for installing the EPSG 
dataset are available,
-         *         or an empty set otherwise.
-         */
-        @Override
-        public Set<String> getAuthorities() {
-            return (directory != null) ? super.getAuthorities() : Set.of();
-        }
-
-        /**
-         * Returns {@code null} since the user is presumed to have downloaded 
the files himself.
-         *
-         * @return the terms of use in plain text or HTML, or {@code null} if 
the license is presumed already accepted.
-         */
-        @Override
-        public String getLicense(String authority, Locale locale, String 
mimeType) {
-            return null;
-        }
-
-        /**
-         * Opens the input stream for the SQL script of the given name.
-         * The returned input stream does not need to be buffered.
-         *
-         * @param  name  name of the script file to open.
-         * @return an input stream opened of the given script file, or {@code 
null} if the resource was not found.
-         * @throws IOException if an error occurred while opening the file.
-         */
-        @Override
-        protected InputStream openStream(final String name) throws IOException 
{
-            return (directory != null) ? 
Files.newInputStream(directory.resolve(name)) : null;
-        }
-    }
 }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
index 55c0a8653b..bd68bcbf52 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
@@ -249,8 +249,8 @@ final class TableInfo {
     }
 
     /**
-     * Returns the class of objects created from the given table. The given 
table name should be one of
-     * the values enumerated in the {@code "Table Name"} types of the {@code 
EPSG_Prepare.sql} file.
+     * Returns the class of objects created from the given table. The given 
table name should be one
+     * of the values enumerated in the {@code "Table Name"} types of the 
{@code Prepare.sql} file.
      * The name may be prefixed by {@code "epsg_"} and may contain 
abbreviations of the full name.
      * For example, {@code "epsg_coordoperation"} is considered as a match for 
{@code "Coordinate_Operation"}.
      *
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
index 893adf3297..bd84bb66f0 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
@@ -20,6 +20,7 @@ import java.util.Set;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.io.IOException;
+import java.net.URISyntaxException;
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.Statement;
@@ -52,14 +53,12 @@ import org.apache.sis.metadata.sql.TestDatabase;
  * so we want to opportunistically verify the result immediately after 
database creation
  * by using the {@code EPSGFactory} for creating a few CRS.
  *
- * <p>This test requires that the {@code 
$SIS_DATA/Databases/ExternalSources/EPSG} directory
+ * <p>This test requires that the {@code org.apache.sis.referencing.epsg} 
optional module
  * contains the {@code Tables.sql}, {@code Data.sql} and {@code FKeys.sql} 
files.
- * An easy setup is to set the above-cited {@code EPSG} directory as a 
symbolic link
- * to the {@code EPSG} directory of the
- * <a href="https://sis.apache.org/source.html#non-free";>SIS non-free 
directory</a>.</p>
+ * See <a href="https://sis.apache.org/source.html#non-free";>source 
checkout</a>.</p>
  *
- * <p>Every databases created by this test suite exist only in memory.
- * This class does not write to disk, except temporary files for some 
databases.</p>
+ * <p>The Derby and HSQL databases created by this test suite exist only in 
memory.
+ * This class does not write to disk, except for the PostgreSQL database.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
@@ -77,11 +76,12 @@ public final class EPSGInstallerTest extends 
TestCaseWithLogs {
      *
      * @return provider of SQL scripts to execute for building the EPSG 
geodetic dataset.
      * @throws IOException if an I/O operation was required and failed.
+     * @throws URISyntaxException if an error occurred while locating the 
directory of the scripts.
      */
-    private static InstallationScriptProvider getScripts() throws IOException {
-        final var scripts = new InstallationScriptProvider.Default(null);
+    private static InstallationScriptProvider getScripts() throws IOException, 
URISyntaxException {
+        final var scripts = new EPSGScriptProvider();
         assumeTrue(scripts.getAuthorities().contains(Constants.EPSG),
-                "Scripts not found in the \"Databases/ExternalSources/EPSG\" 
directory.");
+                "Scripts not found in the \"org.apache.sis.referencing.epsg\" 
optional module.");
         return scripts;
     }
 
@@ -89,7 +89,7 @@ public final class EPSGInstallerTest extends TestCaseWithLogs 
{
      * Tests the creation of an EPSG database on Derby.
      * This test is skipped if the SQL scripts are not found.
      *
-     * <p>See {@link TestDatabase} javadoc if there is a need to inspect 
content of that in-memory database.</p>
+     * <p>See {@link TestDatabase} Javadoc if there is a need to inspect the 
content of that in-memory database.</p>
      *
      * @throws Exception if an error occurred while creating the database.
      */
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGScriptProvider.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGScriptProvider.java
new file mode 100644
index 0000000000..6317bbea20
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGScriptProvider.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.factory.sql;
+
+import java.util.Set;
+import java.util.Locale;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import org.apache.sis.pending.jdk.JDK22;
+import org.apache.sis.util.privy.Constants;
+
+// Test dependencies
+import static org.junit.jupiter.api.Assertions.*;
+
+
+/**
+ * A script provider which uses the scripts in the {@code 
org.apache.sis.referencing.epsg} optional module, if the scripts are present.
+ * For licensing reasons, those scripts must be installed manually as 
documented in the
+ * <a href="https://sis.apache.org/source.html#non-free";>source checkout web 
page</a>.
+ * This class expects the files to have those exact names:
+ *
+ * <ul>
+ *   <li>{@code Prepare.sql} (from Apache <abbr>SIS</abbr>)</li>
+ *   <li>{@code Tables.sql} (derived from <abbr>EPSG</abbr>)</li>
+ *   <li>{@code Data.sql}   (derived from <abbr>EPSG</abbr>)</li>
+ *   <li>{@code FKeys.sql}  (derived from <abbr>EPSG</abbr>)</li>
+ *   <li>{@code Finish.sql}  (from Apache <abbr>SIS</abbr>)</li>
+ * </ul>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+final class EPSGScriptProvider extends InstallationScriptProvider {
+    /**
+     * The source code directory where to look for the <abbr>SQL</abbr> 
scripts.
+     */
+    private final Path directory;
+
+    /**
+     * Creates the provider.
+     *
+     * @param locale  the locale for warning messages, if any.
+     */
+    EPSGScriptProvider() throws IOException, URISyntaxException {
+        super(Constants.EPSG, "Prepare.sql", "Tables.sql", "Data.sql", 
"FKeys.sql", "Finish.sql");
+        final Class<?> member = EPSGScriptProvider.class;
+        final URL url = member.getResource(member.getSimpleName() + ".class");
+        assertNotNull(url, "Class not found.");
+        assertNotEquals("jar", url.getProtocol());
+        Path parent = Path.of(url.toURI());
+        Path subproject;
+        do {
+            parent = parent.getParent();
+            assertNotNull(parent, "Project root not found.");
+            subproject = parent.resolve("optional");
+        } while (!Files.isDirectory(subproject));
+        directory = JDK22.resolve(subproject, "src", 
"org.apache.sis.referencing.epsg", "main",
+                            "org", "apache", "sis", "referencing", "factory", 
"sql", "epsg");
+        assertTrue(Files.isDirectory(directory));
+    }
+
+    /**
+     * Returns {@code "EPSG"} if the non-free scripts exist in the {@code 
org.apache.sis.referencing.epsg} optional module,
+     * or an empty set otherwise.
+     *
+     * @return {@code "EPSG"} if the <abbr>SQL</abbr> scripts for installing 
the EPSG dataset are available,
+     *         or an empty set otherwise.
+     */
+    @Override
+    public Set<String> getAuthorities() {
+        return Files.isReadable(directory.resolve("Data.sql")) ? 
super.getAuthorities() : Set.of();
+    }
+
+    /**
+     * Returns {@code null} since the users are presumed to have downloaded 
the files themselves.
+     *
+     * @return the terms of use in plain text or HTML, or {@code null} if the 
license is presumed already accepted.
+     */
+    @Override
+    public String getLicense(String authority, Locale locale, String mimeType) 
{
+        return null;
+    }
+
+    /**
+     * Opens the input stream for the <abbr>SQL</abbr> script of the given 
name.
+     * The returned input stream does not need to be buffered.
+     *
+     * @param  name  name of the script file to open.
+     * @return an input stream opened of the given script file.
+     * @throws IOException if an error occurred while opening the file.
+     */
+    @Override
+    protected InputStream openStream(final String name) throws IOException {
+        return Files.newInputStream(directory.resolve(name));
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/InstallationResources.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/InstallationResources.java
index e758886961..1f0a7aee56 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/InstallationResources.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/InstallationResources.java
@@ -78,7 +78,7 @@ public abstract class InstallationResources {
     }
 
     /**
-     * Returns all installation resources found on the module path, regardless 
is supported or not.
+     * Returns all installation resources found on the module path, regardless 
if supported or not.
      * Callers should filter the services for executing only those where 
{@link #getAuthorities()}
      * returns a non-empty set.
      *
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
index bde879cdcb..557c20896b 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
@@ -253,11 +253,6 @@ public class Errors extends IndexedResourceBundle {
          */
         public static final short DuplicatedElement_1 = 37;
 
-        /**
-         * File “{0}” is referenced more than once.
-         */
-        public static final short DuplicatedFileReference_1 = 38;
-
         /**
          * Name or identifier “{0}” is used more than once.
          */
@@ -504,7 +499,7 @@ public class Errors extends IndexedResourceBundle {
         /**
          * The position is indeterminate.
          */
-        public static final short IndeterminatePosition = 206;
+        public static final short IndeterminatePosition = 38;
 
         /**
          * Index {0} is out of bounds.
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
index 71906b3ab7..a17983d55b 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
@@ -63,7 +63,6 @@ DatabaseUpdateFailure_3           = Failed to 
{0,choice,0#insert|1#update} recor
 DeadThread_1                      = Thread \u201c{0}\u201d is dead.
 DisposedInstanceOf_1              = This instance of \u2018{0}\u2019 has been 
disposed.
 DuplicatedElement_1               = Element \u201c{0}\u201d is duplicated.
-DuplicatedFileReference_1         = File \u201c{0}\u201d is referenced more 
than once.
 DuplicatedIdentifier_1            = Name or identifier \u201c{0}\u201d is used 
more than once.
 DuplicatedNumber_1                = Value {0,number} is used more than once.
 DuplicatedOption_1                = Option \u201c{0}\u201d is duplicated.
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
index 218d66de63..a2523ca032 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
@@ -60,7 +60,6 @@ DatabaseUpdateFailure_3           = \u00c9chec lors de 
{0,choice,0#l\u2019insert
 DeadThread_1                      = La t\u00e2che \u00ab\u202f{0}\u202f\u00bb 
est morte.
 DisposedInstanceOf_1              = Cette instance de \u2018{0}\u2019 a 
\u00e9t\u00e9 dispos\u00e9e.
 DuplicatedElement_1               = L\u2019\u00e9l\u00e9ment 
\u00ab\u202f{0}\u202f\u00bb est dupliqu\u00e9.
-DuplicatedFileReference_1         = Le fichier \u00ab\u202f{0}\u202f\u00bb est 
r\u00e9f\u00e9renc\u00e9 plus d\u2019une fois.
 DuplicatedIdentifier_1            = Le nom ou l\u2019identifiant 
\u00ab\u202f{0}\u202f\u00bb est utilis\u00e9 plus d\u2019une fois.
 DuplicatedNumber_1                = La valeur {0,number} est utilis\u00e9e 
plus d\u2019une fois.
 DuplicatedOption_1                = L\u2019option \u00ab\u202f{0}\u202f\u00bb 
est dupliqu\u00e9e.
diff --git 
a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore
 
b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore
index f7436babfc..f3e0b73bd5 100644
--- 
a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore
+++ 
b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore
@@ -1,7 +1,8 @@
 # Those files must be put manually for licensing reasons.
 # See README.md for more details.
-Data.sql
-FKeys.sql
+
 LICENSE.html
 LICENSE.txt
 Tables.sql
+Data.sql
+FKeys.sql
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSG_Finish.sql
 
b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/Finish.sql
similarity index 100%
rename from 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSG_Finish.sql
rename to 
optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/Finish.sql
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSG_Prepare.sql
 
b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/Prepare.sql
similarity index 100%
rename from 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSG_Prepare.sql
rename to 
optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/Prepare.sql
diff --git 
a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java
 
b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java
index 333a9b1dbf..6db471fc30 100644
--- 
a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java
+++ 
b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java
@@ -17,6 +17,7 @@
 package org.apache.sis.referencing.factory.sql.epsg;
 
 import java.util.Locale;
+import java.util.StringJoiner;
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -28,14 +29,14 @@ import 
org.apache.sis.referencing.factory.sql.InstallationScriptProvider;
 
 
 /**
- * Provides SQL scripts for creating a local copy of the EPSG geodetic dataset.
- * Provides also a copy of the <a 
href="https://epsg.org/terms-of-use.html";>EPSG terms of use</a>,
- * which should be accepted by users before the EPSG dataset can be installed.
+ * Provides <abbr>SQL</abbr> scripts for creating a local copy of the 
<abbr>EPSG</abbr> geodetic dataset.
+ * Provides also a copy of the <a 
href="https://epsg.org/terms-of-use.html";><abbr>EPSG</abbr> Terms of Use</a>,
+ * which should be accepted by users before the <abbr>EPSG</abbr> dataset can 
be installed.
  *
- * <p><b>Notice</b></p>
- * EPSG is maintained by the <a href="http://www.iogp.org/";>International 
Association of Oil and Gas Producers</a>
- * (IOGP) Surveying &amp; Positioning Committee. The SQL scripts are given by 
this class with identical content,
- * but in a more compact format.
+ * <h2>Notice</h2>
+ * <abbr>EPSG</abbr> is maintained by the <a 
href="http://www.iogp.org/";>International Association of Oil and Gas 
Producers</a>
+ * (<abbr>IOGP</abbr>) Surveying &amp; Positioning Committee. The 
<abbr>SQL</abbr> scripts given by this class are derived from
+ * the <abbr>EPSG</abbr> scripts, but in a more compact format and with some 
<abbr>EPSG</abbr> lineage metadata omitted.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.5
@@ -48,11 +49,11 @@ public class ScriptProvider extends 
InstallationScriptProvider {
      * Creates a new EPSG scripts provider.
      */
     public ScriptProvider() {
-        super(Constants.EPSG, PREPARE, "Tables.sql", "Data.sql", "FKeys.sql", 
FINISH);
+        super(Constants.EPSG, "Prepare.sql", "Tables.sql", "Data.sql", 
"FKeys.sql", "Finish.sql");
     }
 
     /**
-     * Returns a copy of EPSG terms of use.
+     * Returns a copy of <abbr>EPSG</abbr> terms of use.
      *
      * @param  authority  one of the values returned by {@link 
#getAuthorities()}.
      * @param  locale     the preferred locale for the terms of use.
@@ -79,20 +80,19 @@ public class ScriptProvider extends 
InstallationScriptProvider {
         if (in == null) {
             throw new FileNotFoundException(filename);
         }
-        final StringBuilder buffer = new StringBuilder();
-        final String lineSeparator = System.lineSeparator();
-        try (BufferedReader r = new BufferedReader(new InputStreamReader(in, 
"UTF-8"))) {
+        final var buffer = new StringJoiner(System.lineSeparator(), "", 
System.lineSeparator());
+        try (var reader = new BufferedReader(new InputStreamReader(in, 
"UTF-8"))) {
             String line;
-            while ((line = r.readLine()) != null) {
-                buffer.append(line).append(lineSeparator);
+            while ((line = reader.readLine()) != null) {
+                buffer.add(line);
             }
         }
         return buffer.toString();
     }
 
     /**
-     * Returns the content for the SQL script of the given name.
-     * The file encoding is UTF-8.
+     * Returns the content for the <abbr>SQL</abbr> script of the given name.
+     * The file encoding is <abbr>UTF</abbr>-8.
      *
      * @param name  either {@code "Tables.sql"}, {@code "Data.sql"} or {@code 
"FKeys.sql"}.
      * @return the SQL script of the given name, or {@code null} if the given 
name is not one of the expected names.

Reply via email to