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

commit 559ad8b78c2a70396588433d1ec5fe6f6aceeeca
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Jun 28 15:39:04 2025 +0200

    Replace the MS-Access SQL dialect by ANSI SQL in EPSG factory.
    For example, use "Datum" instead of [Datum] in hard-coded queries
    (before this commit, [Datum] was replaced by "Datum" at runtime).
---
 .../sis/metadata/sql/privy/ScriptRunner.java       |  12 +-
 .../referencing/factory/sql/EPSGCodeFinder.java    |  10 +-
 .../referencing/factory/sql/EPSGDataAccess.java    | 176 +++++-----
 .../sis/referencing/factory/sql/EPSGFactory.java   |  14 +-
 .../sis/referencing/factory/sql/EPSGInstaller.java |  18 +-
 .../sis/referencing/factory/sql/SQLTranslator.java | 377 +++++++++++----------
 .../sis/referencing/factory/sql/TableInfo.java     |  69 ++--
 .../sis/referencing/factory/sql/package-info.java  |   4 +-
 .../referencing/internal/SignReversalComment.java  |   4 +-
 .../operation/provider/AbstractProvider.java       |   8 +-
 .../referencing/factory/sql/EPSGInstallerTest.java |   5 +-
 .../sis/referencing/factory/sql/TableInfoTest.java |   7 +-
 .../org/apache/sis/util/CharSequencesTest.java     |  55 +--
 13 files changed, 408 insertions(+), 351 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/ScriptRunner.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/ScriptRunner.java
index 4ca39c62ff..4883581f48 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/ScriptRunner.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/ScriptRunner.java
@@ -384,10 +384,14 @@ public class ScriptRunner implements AutoCloseable {
      * The replacement is performed only for occurrences outside identifiers 
or texts.
      *
      * <h4>Example</h4>
-     * This is used for mapping the table names in the EPSG scripts to table 
names as they were in the MS-Access
-     * flavor of EPSG database. It may also contains the mapping between SQL 
keywords used in the SQL scripts to
-     * SQL keywords understood by the database. For example if a database does 
not support the {@code "TEXT"}
-     * data type, it may be replaced by {@code "LONG VARCHAR"}.
+     * This is used for mapping the <abbr>EPSG</abbr> table names from the 
mixed-cases convention used in
+     * the {@code org.apache.sis.referencing.epsg} module to the lower-cases 
convention which is actually
+     * used if the user installed the <abbr>EPSG</abbr> database manually 
(there is more differences than
+     * only the case).
+     *
+     * <p>Another example is the replacement of <abbr>SQL</abbr> keywords used 
in the scripts by keywords
+     * understood by the database. For example, if a database does not support 
the {@code "TEXT"} data type,
+     * this method can be used for replacing {@code "TEXT"} by {@code "LONG 
VARCHAR"}.</p>
      *
      * <h4>Limitation</h3>
      * The {@code inScript} word to replace must be a single word with no 
space.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
index 45a6228236..a925a30e9b 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
@@ -220,7 +220,7 @@ final class EPSGCodeFinder extends IdentifiedObjectFinder {
          */
         @Override
         public final String toString() {
-            final StringBuilder buffer = new StringBuilder(50);
+            final var buffer = new StringBuilder(50);
             appendToWhere(buffer, false);
             return buffer.toString();
         }
@@ -382,7 +382,7 @@ crs:    if (isInstance(CoordinateReferenceSystem.class, 
object)) {
          * but does not execute it now. Note that this block overwrites the 
`buffer` content,
          * so that buffer shall not contain valuable information yet.
          */
-        final StringBuilder buffer = new StringBuilder(350);     // Temporary 
buffer for building SQL query.
+        final var buffer = new StringBuilder(350);     // Temporary buffer for 
building SQL query.
         final Set<String> namePatterns;
         final String aliasSQL;
         if (ArraysExt.containsIdentity(filters, Condition.NAME)) {
@@ -392,7 +392,9 @@ crs:    if (isInstance(CoordinateReferenceSystem.class, 
object)) {
                 namePatterns.add(toDatumPattern(id.tip().toString(), buffer));
             }
             buffer.setLength(0);
-            buffer.append("SELECT OBJECT_CODE FROM [Alias] WHERE 
OBJECT_TABLE_NAME='").append(table.unquoted()).append("' AND ");
+            buffer.append("SELECT OBJECT_CODE FROM \"Alias\" WHERE 
OBJECT_TABLE_NAME='")
+                  .append(dao.translator.toActualTableName(table.unquoted()))
+                  .append("' AND ");
             // PostgreSQL does not require explicit cast when the value is a 
literal instead of "?".
             appendFilterByName(namePatterns, "ALIAS", buffer);
             aliasSQL = dao.translator.apply(buffer.toString());
@@ -457,7 +459,7 @@ crs:    if (isInstance(CoordinateReferenceSystem.class, 
object)) {
              * At this point the SQL query is complete. Run it, preserving 
order.
              * Then sort the result by taking in account the supersession 
table.
              */
-            final Set<String> result = new LinkedHashSet<>();       // We need 
to preserve order in this set.
+            final var result = new LinkedHashSet<String>();     // We need to 
preserve order in this set.
             try (ResultSet r = 
stmt.executeQuery(dao.translator.apply(buffer.toString()))) {
                 while (r.next()) {
                     result.add(r.getString(1));
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 f02f2a29e7..3f3f06c54c 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
@@ -19,7 +19,6 @@ package org.apache.sis.referencing.factory.sql;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.Map;
-import java.util.List;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedHashMap;
@@ -43,6 +42,7 @@ import java.sql.Statement;
 import java.sql.SQLException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.time.LocalDate;
 import java.time.temporal.Temporal;
 import javax.measure.Unit;
 import javax.measure.quantity.Angle;
@@ -149,11 +149,6 @@ import org.opengis.referencing.ObjectDomain;
  * in the common case where only a few EPSG codes are used by an application.
  * {@code EPSGDataAccess.createFoo(String)} methods do not cache by themselves 
and query the database on every invocation.
  *
- * <h2>SQL dialects</h2>
- * Because the primary distribution format for the EPSG dataset is MS-Access, 
this class uses SQL statements formatted
- * for the MS-Access dialect. For usage with other database software products 
like PostgreSQL or Derby,
- * a {@link SQLTranslator} instance is provided to the constructor.
- *
  * @author  Yann Cézard (IRD)
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Rueben Schulz (UBC)
@@ -199,7 +194,7 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
     @Workaround(library = "EPSG:6401-6420", version = "8.9")        // 
Deprecated in 2002 but still present in 2016.
     private static final Map<Integer,Integer> DEPRECATED_CS = deprecatedCS();
     static Map<Integer,Integer> deprecatedCS() {
-        final Map<Integer,Integer> m = new HashMap<>(24);
+        final var m = new HashMap<Integer,Integer>(24);
 
         // Ellipsoidal 2D CS. Axes: latitude, longitude. Orientations: north, 
east. UoM: degree
         Integer replacement = 6422;
@@ -332,8 +327,10 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
     protected final Connection connection;
 
     /**
-     * The translator from the SQL statements using MS-Access dialect
-     * to SQL statements using the dialect of the actual database.
+     * The translator from the <abbr>SQL</abbr> statements hard-coded in this 
class to
+     * <abbr>SQL</abbr> statements compatible with the actual 
<abbr>EPSG</abbr> database.
+     * This translator may also change the schema and table names used in the 
queries
+     * in the actual database uses different names.
      */
     protected final SQLTranslator translator;
 
@@ -349,17 +346,22 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
      *
      * @param owner       the {@code EPSGFactory} which is creating this Data 
Access Object (DAO).
      * @param connection  the connection to the underlying EPSG database.
-     * @param translator  the translator from the SQL statements using 
MS-Access dialect
-     *                    to SQL statements using the dialect of the actual 
database.
+     * @param translator  translator from the <abbr>SQL</abbr> statements 
hard-coded in this class to
+     *                    <abbr>SQL</abbr> statements compatible with the 
actual <abbr>EPSG</abbr> database.
+     * @throws SQLException if an error occurred with the database connection.
      *
      * @see EPSGFactory#newDataAccess(Connection, SQLTranslator)
      */
-    protected EPSGDataAccess(final EPSGFactory owner, final Connection 
connection, final SQLTranslator translator) {
+    protected EPSGDataAccess(final EPSGFactory owner, final Connection 
connection, final SQLTranslator translator)
+            throws SQLException
+    {
         this.owner      = owner;
         this.connection = Objects.requireNonNull(connection);
         this.translator = Objects.requireNonNull(translator);
         this.namespace  = owner.nameFactory.createNameSpace(
                           owner.nameFactory.createLocalName(null, 
Constants.IOGP), null);
+        connection.setCatalog(translator.getCatalog());
+        connection.setSchema (translator.getSchema());
     }
 
     /**
@@ -409,7 +411,7 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
         /*
          * We do not cache this citation because the caching service is 
already provided by ConcurrentAuthorityFactory.
          */
-        final DefaultCitation c = new DefaultCitation("EPSG Geodetic Parameter 
Dataset");
+        final var c = new DefaultCitation("EPSG Geodetic Parameter Dataset");
         c.setIdentifiers(Set.of(new ImmutableIdentifier(null, null, 
Constants.EPSG)));
         try {
             /*
@@ -417,7 +419,7 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
              * instead of UTC because the date is for information purpose 
only, and the local timezone is
              * more likely to be shown nicely (without artificial hours) to 
the user.
              */
-            final String query = translator.apply("SELECT VERSION_NUMBER, 
VERSION_DATE FROM [Version History]" +
+            final String query = translator.apply("SELECT VERSION_NUMBER, 
VERSION_DATE FROM \"Version History\"" +
                                                   " ORDER BY VERSION_DATE 
DESC, VERSION_HISTORY_CODE DESC");
             String version = null;
             try (Statement stmt = connection.createStatement();
@@ -428,7 +430,7 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
                     final Date date = result.getDate(2);                       
     // Local timezone.
                     if (version != null && date != null) {                     
     // Paranoiac check.
                         c.setEdition(new SimpleInternationalString(version));
-                        c.setEditionDate(date);
+                        c.setEditionDate(LocalDate.ofEpochDay(date.getTime() / 
Constants.MILLISECONDS_PER_DAY));
                         break;
                     }
                 }
@@ -462,7 +464,7 @@ addURIs:    for (int i=0; ; i++) {
                     }
                     default: break addURIs;     // Finished adding all URIs.
                 }
-                final DefaultOnlineResource r = new DefaultOnlineResource();
+                final var r = new DefaultOnlineResource();
                 try {
                     r.setLinkage(new URI(url));
                 } catch (URISyntaxException exception) {
@@ -685,6 +687,7 @@ addURIs:    for (int i=0; ; i++) {
     private int[] toPrimaryKeys(final String table, final String codeColumn, 
final String nameColumn, final String... codes)
             throws SQLException, FactoryException
     {
+        String actualTable = null;
         final int[] primaryKeys = new int[codes.length];
 codes:  for (int i=0; i<codes.length; i++) {
             final String code = codes[i];
@@ -694,15 +697,19 @@ codes:  for (int i=0; i<codes.length; i++) {
                  * We search first in the primary table. If no name is not 
found there, then we
                  * will search in the aliases table as a fallback.
                  */
+                if (actualTable == null) {
+                    actualTable = translator.toActualTableName(table);
+                }
                 final String pattern = SQLUtilities.toLikePattern(code, false);
                 Integer resolved = null;
                 boolean alias = false;
                 do {
                     PreparedStatement stmt;
                     if (alias) {
-                        // Note: "OBJECT_TABLE_NAME=?" is handled in a special 
way by SQLTranslator.
-                        stmt = prepareStatement("AliasKey", "SELECT 
OBJECT_CODE, ALIAS FROM [Alias] WHERE OBJECT_TABLE_NAME=? AND ALIAS LIKE ?");
-                        stmt.setString(1, table);
+                        stmt = prepareStatement("AliasKey",
+                                "SELECT OBJECT_CODE, ALIAS FROM \"Alias\"" +
+                                " WHERE OBJECT_TABLE_NAME=? AND ALIAS LIKE ?");
+                        stmt.setString(1, actualTable);
                         stmt.setString(2, pattern);
                     } else {
                         /*
@@ -723,7 +730,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                         if (stmt == null) {
                             stmt = 
connection.prepareStatement(translator.apply(
                                     "SELECT " + codeColumn + ", " + nameColumn 
+
-                                    " FROM [" + table + "] WHERE " + 
nameColumn + " LIKE ?"));
+                                    " FROM \"" + actualTable + "\" WHERE " + 
nameColumn + " LIKE ?"));
                             statements.put(KEY, stmt);
                             lastTableForName = table;
                         }
@@ -775,7 +782,7 @@ codes:  for (int i=0; i<codes.length; i++) {
             final String sql, final String... codes) throws SQLException, 
FactoryException
     {
         assert Thread.holdsLock(this);
-        assert sql.contains('[' + table + ']') : table;
+        assert sql.contains('"' + table + '"') : table;
         assert (codeColumn == null) || sql.contains(codeColumn) || 
table.equals("Area") : codeColumn;
         assert (nameColumn == null) || sql.contains(nameColumn) || 
table.equals("Area") : nameColumn;
         return executeQuery(table, sql, toPrimaryKeys(table, codeColumn, 
nameColumn, codes));
@@ -1044,9 +1051,9 @@ codes:  for (int i=0; i<codes.length; i++) {
         String reason = null;
         Object replacedBy = null;
         try (ResultSet result = executeMetadataQuery("Deprecation",
-                "SELECT DEPRECATION_REASON, REPLACED_BY FROM [Deprecation]" +
-                " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?", table, code))
-                // Note: "OBJECT_TABLE_NAME=?" is handled in a special way by 
SQLTranslator.
+                "SELECT DEPRECATION_REASON, REPLACED_BY FROM \"Deprecation\"" +
+                " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?",
+                translator.toActualTableName(table), code))
         {
             while (result.next()) {
                 reason     = getOptionalString (result, 1);
@@ -1060,13 +1067,13 @@ codes:  for (int i=0; i<codes.length; i++) {
             replacedBy = replacedBy.toString();
         }
         /*
-         * Try to infer the method name from the table name. For example if 
the deprecated code was found in
-         * the [Coordinate Reference System] table, then we declare 
createCoordinateReferenceSystem(String)
+         * Try to infer the method name from the table name. For example, if 
the deprecated code was found in
+         * the "Coordinate Reference System" table, then we declare 
`createCoordinateReferenceSystem(String)`
          * as the source of the log message.
          */
         String method = "create";
         for (final TableInfo info : TableInfo.EPSG) {
-            if (TableInfo.tableMatches(info.table, table)) {
+            if (info.tableMatches(table)) {
                 method += info.type.getSimpleName();
                 break;
             }
@@ -1110,14 +1117,14 @@ codes:  for (int i=0; i<codes.length; i++) {
          *   - We do not perform this replacement directly in our EPSG 
database because ASCII letters are more
          *     convenient for implementing accent-insensitive searches.
          */
-        final List<GenericName> aliases = new ArrayList<>();
+        final var aliases = new ArrayList<GenericName>();
         try (ResultSet result = executeMetadataQuery("Alias",
                 "SELECT NAMING_SYSTEM_NAME, ALIAS" +
-                " FROM [Alias] INNER JOIN [Naming System]" +
-                  " ON [Alias].NAMING_SYSTEM_CODE =" +
-                " [Naming System].NAMING_SYSTEM_CODE" +
-                " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?", table, code))
-                // Note: "OBJECT_TABLE_NAME=?" is handled in a special way by 
SQLTranslator.
+                " FROM \"Alias\" INNER JOIN \"Naming System\"" +
+                  " ON \"Alias\".NAMING_SYSTEM_CODE =" +
+                " \"Naming System\".NAMING_SYSTEM_CODE" +
+                " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?",
+                translator.toActualTableName(table), code))
         {
             while (result.next()) {
                 final String naming = getOptionalString(result, 1);
@@ -1153,7 +1160,7 @@ codes:  for (int i=0; i<codes.length; i++) {
             properties.put(NamedIdentifier.VERSION_KEY,   version);
             properties.put(NamedIdentifier.AUTHORITY_KEY, authority);
             properties.put(AbstractIdentifiedObject.LOCALE_KEY, locale);
-            final NamedIdentifier id = new NamedIdentifier(properties);
+            final var id = new NamedIdentifier(properties);
             properties.clear();
             properties.put(IdentifiedObject.NAME_KEY, id);
         }
@@ -1348,7 +1355,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " PROJECTION_CONV_CODE,"        +     // [11] For 
ProjectedCRS
                       " CMPD_HORIZCRS_CODE,"          +     // [12] For 
CompoundCRS only
                       " CMPD_VERTCRS_CODE"            +     // [13] For 
CompoundCRS only
-                " FROM [Coordinate Reference System]" +
+                " FROM \"Coordinate Reference System\"" +
                 " WHERE COORD_REF_SYS_CODE = ?", code))
         {
             while (result.next()) {
@@ -1632,7 +1639,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " DEPRECATED," +
                       " ELLIPSOID_CODE," +          // Only for geodetic type
                       " PRIME_MERIDIAN_CODE" +      // Only for geodetic type
-                " FROM [Datum]" +
+                " FROM \"Datum\"" +
                 " WHERE DATUM_CODE = ?", code))
         {
             while (result.next()) {
@@ -1773,23 +1780,23 @@ codes:  for (int i=0; i<codes.length; i++) {
         if (code == BursaWolfInfo.TARGET_DATUM) {
             return null;
         }
-        final List<BursaWolfInfo> bwInfos = new ArrayList<>();
+        final var bwInfos = new ArrayList<BursaWolfInfo>();
         try (ResultSet result = executeQuery("BursaWolfParametersSet",
                 "SELECT COORD_OP_CODE," +
                       " COORD_OP_METHOD_CODE," +
                       " TARGET_CRS_CODE," +
                       " AREA_OF_USE_CODE"+
-                " FROM [Coordinate_Operation]" +
+                " FROM \"Coordinate_Operation\"" +
                " WHERE DEPRECATED=0" +           // Do not put spaces around 
"=" - SQLTranslator searches for this exact match.
                  " AND TARGET_CRS_CODE = "       + BursaWolfInfo.TARGET_CRS +
                  " AND COORD_OP_METHOD_CODE >= " + 
BursaWolfInfo.MIN_METHOD_CODE +
                  " AND COORD_OP_METHOD_CODE <= " + 
BursaWolfInfo.MAX_METHOD_CODE +
                  " AND SOURCE_CRS_CODE IN " +
-               "(SELECT COORD_REF_SYS_CODE FROM [Coordinate Reference System] 
WHERE DATUM_CODE = ?)" +
+               "(SELECT COORD_REF_SYS_CODE FROM \"Coordinate Reference 
System\" WHERE DATUM_CODE = ?)" +
             " ORDER BY TARGET_CRS_CODE, COORD_OP_ACCURACY, COORD_OP_CODE 
DESC", code))
         {
             while (result.next()) {
-                final BursaWolfInfo info = new BursaWolfInfo(
+                final var info = new BursaWolfInfo(
                         getInteger(code, result, 1),                // 
Operation
                         getInteger(code, result, 2),                // Method
                         getInteger(code, result, 3),                // Target 
datum
@@ -1818,7 +1825,7 @@ codes:  for (int i=0; i<codes.length; i++) {
         /*
          * Now, iterate over the results and fetch the parameter values for 
each BursaWolfParameters object.
          */
-        final BursaWolfParameters[] parameters = new BursaWolfParameters[size];
+        final var parameters = new BursaWolfParameters[size];
         final Locale locale = getLocale();
         int count = 0;
         for (int i=0; i<size; i++) {
@@ -1840,12 +1847,12 @@ codes:  for (int i=0; i<codes.length; i++) {
             if (!equalsIgnoreMetadata(meridian, datum.getPrimeMeridian())) {
                 continue;
             }
-            final BursaWolfParameters bwp = new BursaWolfParameters(datum, 
info.getDomainOfValidity(owner));
+            final var bwp = new BursaWolfParameters(datum, 
info.getDomainOfValidity(owner));
             try (ResultSet result = executeQuery("BursaWolfParameters",
                 "SELECT PARAMETER_CODE," +
                       " PARAMETER_VALUE," +
                       " UOM_CODE" +
-                " FROM [Coordinate_Operation Parameter Value]" +
+                " FROM \"Coordinate_Operation Parameter Value\"" +
                 " WHERE COORD_OP_CODE = ?" +
                   " AND COORD_OP_METHOD_CODE = ?", info.operation, 
info.method))
             {
@@ -1905,7 +1912,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " UOM_CODE," +
                       " REMARKS," +
                       " DEPRECATED" +
-                " FROM [Ellipsoid]" +
+                " FROM \"Ellipsoid\"" +
                 " WHERE ELLIPSOID_CODE = ?", code))
         {
             while (result.next()) {
@@ -1995,7 +2002,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " UOM_CODE," +
                       " REMARKS," +
                       " DEPRECATED" +
-                " FROM [Prime Meridian]" +
+                " FROM \"Prime Meridian\"" +
                 " WHERE PRIME_MERIDIAN_CODE = ?", code))
         {
             while (result.next()) {
@@ -2053,7 +2060,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " AREA_NORTH_BOUND_LAT," +
                       " AREA_WEST_BOUND_LON," +
                       " AREA_EAST_BOUND_LON" +
-                " FROM [Area]" +
+                " FROM \"Area\"" +
                 " WHERE AREA_CODE = ?", code))
         {
             while (result.next()) {
@@ -2079,7 +2086,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                     bbox = new DefaultGeographicBoundingBox(xmin, xmax, ymin, 
ymax);
                 }
                 if (description != null || bbox != null) {
-                    DefaultExtent extent = new DefaultExtent(description, 
bbox, null, null);
+                    var extent = new DefaultExtent(description, bbox, null, 
null);
                     extent.transitionTo(DefaultExtent.State.FINAL);
                     returnValue = ensureSingleton(extent, returnValue, code);
                 }
@@ -2134,7 +2141,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " DIMENSION," +
                       " REMARKS," +
                       " DEPRECATED" +
-                " FROM [Coordinate System]" +
+                " FROM \"Coordinate System\"" +
                 " WHERE COORD_SYS_CODE = ?", code))
         {
             while (result.next()) {
@@ -2241,9 +2248,6 @@ codes:  for (int i=0; i<codes.length; i++) {
     /**
      * Returns the coordinate system axis from an EPSG code for a {@link 
CoordinateSystem}.
      *
-     * <p><strong>WARNING:</strong> The EPSG database uses "{@code ORDER}" as 
a column name.
-     * This is tolerated by Access, but MySQL does not accept that name.</p>
-     *
      * @param  cs         the EPSG code for the coordinate system.
      * @param  dimension  of the coordinate system, which is also the size of 
the returned array.
      * @return an array of coordinate system axis.
@@ -2254,12 +2258,12 @@ codes:  for (int i=0; i<codes.length; i++) {
             throws SQLException, FactoryException
     {
         int i = 0;
-        final CoordinateSystemAxis[] axes = new 
CoordinateSystemAxis[dimension];
+        final var axes = new CoordinateSystemAxis[dimension];
         try (ResultSet result = executeQuery("AxisOrder",
                 "SELECT COORD_AXIS_CODE" +
-                " FROM [Coordinate Axis]" +
+                " FROM \"Coordinate Axis\"" +
                 " WHERE COORD_SYS_CODE = ?" +
-                " ORDER BY [ORDER]", cs))
+                " ORDER BY COORD_AXIS_ORDER", cs))
         {
             while (result.next()) {
                 final String axis = getString(cs, result, 1);
@@ -2314,7 +2318,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " COORD_AXIS_ORIENTATION," +
                       " COORD_AXIS_ABBREVIATION," +
                       " UOM_CODE" +
-                " FROM [Coordinate Axis]" +
+                " FROM \"Coordinate Axis\"" +
                " WHERE COORD_AXIS_CODE = ?", code))
         {
             while (result.next()) {
@@ -2354,7 +2358,7 @@ codes:  for (int i=0; i<codes.length; i++) {
         if (returnValue == null) {
             try (ResultSet result = executeQuery("Coordinate Axis Name",
                     "SELECT COORD_AXIS_NAME, DESCRIPTION, REMARKS" +
-                    " FROM [Coordinate Axis Name]" +
+                    " FROM \"Coordinate Axis Name\"" +
                     " WHERE COORD_AXIS_NAME_CODE = ?", code))
             {
                 while (result.next()) {
@@ -2413,7 +2417,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " FACTOR_C," +
                       " TARGET_UOM_CODE," +
                       " UNIT_OF_MEAS_NAME" +
-                " FROM [Unit of Measure]" +
+                " FROM \"Unit of Measure\"" +
                 " WHERE UOM_CODE = ?", code))
         {
             while (result.next()) {
@@ -2428,8 +2432,10 @@ codes:  for (int i=0; i<codes.length; i++) {
                      */
                     final boolean pb = (b != 1);
                     if (pb || c != 1) {
-                        throw new 
FactoryDataException(error().getString(Errors.Keys.InconsistentAttribute_2,
-                                    pb ? "FACTOR_B" : "FACTOR_C", pb ? b : c));
+                        throw new FactoryDataException(error().getString(
+                                Errors.Keys.InconsistentAttribute_2,
+                                pb ? "FACTOR_B" : "FACTOR_C",
+                                pb ? b : c));
                     }
                 }
                 Unit<?> unit = Units.valueOfEPSG(source);                      
     // Check in our list of hard-coded unit codes.
@@ -2488,7 +2494,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                       " PARAMETER_NAME," +
                       " DESCRIPTION," +
                       " DEPRECATED" +
-                " FROM [Coordinate_Operation Parameter]" +
+                " FROM \"Coordinate_Operation Parameter\"" +
                 " WHERE PARAMETER_CODE = ?", code))
         {
             while (result.next()) {
@@ -2511,7 +2517,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                      */
                     type = Double.class;
                     try (ResultSet r = executeQuery("ParameterType",
-                            "SELECT PARAM_VALUE_FILE_REF FROM 
[Coordinate_Operation Parameter Value]" +
+                            "SELECT PARAM_VALUE_FILE_REF FROM 
\"Coordinate_Operation Parameter Value\"" +
                             " WHERE (PARAMETER_CODE = ?) AND 
PARAM_VALUE_FILE_REF IS NOT NULL", epsg))
                     {
                         while (r.next()) {
@@ -2532,7 +2538,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                      */
                     units = new LinkedHashSet<>();
                     try (ResultSet r = executeQuery("ParameterUnit",
-                            "SELECT UOM_CODE FROM [Coordinate_Operation 
Parameter Value]" +
+                            "SELECT UOM_CODE FROM \"Coordinate_Operation 
Parameter Value\"" +
                             " WHERE (PARAMETER_CODE = ?)" +
                             " GROUP BY UOM_CODE" +
                             " ORDER BY COUNT(UOM_CODE) DESC", epsg))
@@ -2563,7 +2569,8 @@ next:                   while (r.next()) {
                  */
                 InternationalString isReversible = null;
                 try (ResultSet r = executeQuery("ParameterSign",
-                        "SELECT DISTINCT PARAM_SIGN_REVERSAL FROM 
[Coordinate_Operation Parameter Usage]" +
+                        "SELECT DISTINCT PARAM_SIGN_REVERSAL" +
+                        " FROM \"Coordinate_Operation Parameter Usage\"" +
                         " WHERE (PARAMETER_CODE = ?)", epsg))
                 {
                     if (r.next()) {
@@ -2593,8 +2600,7 @@ next:                   while (r.next()) {
                 final Map<String,Object> properties =
                         createProperties("Coordinate_Operation Parameter", 
name, epsg, isReversible, deprecated);
                 properties.put(Identifier.DESCRIPTION_KEY, description);
-                final ParameterDescriptor<?> descriptor = new 
DefaultParameterDescriptor<>(properties,
-                        1, 1, type, valueDomain, null, null);
+                final var descriptor = new 
DefaultParameterDescriptor<>(properties, 1, 1, type, valueDomain, null, null);
                 returnValue = ensureSingleton(descriptor, returnValue, code);
             }
         } catch (SQLException exception) {
@@ -2614,10 +2620,10 @@ next:                   while (r.next()) {
      * @throws SQLException if a SQL statement failed.
      */
     private ParameterDescriptor<?>[] createParameterDescriptors(final Integer 
method) throws FactoryException, SQLException {
-        final List<ParameterDescriptor<?>> descriptors = new ArrayList<>();
+        final var descriptors = new ArrayList<ParameterDescriptor<?>>();
         try (ResultSet result = executeQuery("Coordinate_Operation Parameter 
Usage",
                 "SELECT PARAMETER_CODE" +
-                " FROM [Coordinate_Operation Parameter Usage]" +
+                " FROM \"Coordinate_Operation Parameter Usage\"" +
                 " WHERE COORD_OP_METHOD_CODE = ?" +
                 " ORDER BY SORT_ORDER", method))
         {
@@ -2644,10 +2650,10 @@ next:                   while (r.next()) {
                       " CV.PARAMETER_VALUE," +
                       " CV.PARAM_VALUE_FILE_REF," +
                       " CV.UOM_CODE" +
-               " FROM ([Coordinate_Operation Parameter Value] AS CV" +
-          " INNER JOIN [Coordinate_Operation Parameter] AS CP" +
+               " FROM (\"Coordinate_Operation Parameter Value\" AS CV" +
+          " INNER JOIN \"Coordinate_Operation Parameter\" AS CP" +
                    " ON CV.PARAMETER_CODE = CP.PARAMETER_CODE)" +
-          " INNER JOIN [Coordinate_Operation Parameter Usage] AS CU" +
+          " INNER JOIN \"Coordinate_Operation Parameter Usage\" AS CU" +
                   " ON (CP.PARAMETER_CODE = CU.PARAMETER_CODE)" +
                  " AND (CV.COORD_OP_METHOD_CODE = CU.COORD_OP_METHOD_CODE)" +
                 " WHERE CV.COORD_OP_METHOD_CODE = ?" +
@@ -2745,7 +2751,7 @@ next:                   while (r.next()) {
                       " COORD_OP_METHOD_NAME," +
                       " REMARKS," +
                       " DEPRECATED" +
-                 " FROM [Coordinate_Operation Method]" +
+                 " FROM \"Coordinate_Operation Method\"" +
                 " WHERE COORD_OP_METHOD_CODE = ?", code))
         {
             while (result.next()) {
@@ -2759,8 +2765,8 @@ next:                   while (r.next()) {
                 /*
                  * Note: we do not store the formula at this time, because the 
text is very verbose and rarely used.
                  */
-                final OperationMethod method = new 
DefaultOperationMethod(properties,
-                            new DefaultParameterDescriptorGroup(properties, 1, 
1, descriptors));
+                final var params = new 
DefaultParameterDescriptorGroup(properties, 1, 1, descriptors);
+                final var method = new DefaultOperationMethod(properties, 
params);
                 returnValue = ensureSingleton(method, returnValue, code);
             }
         } catch (SQLException exception) {
@@ -2814,7 +2820,7 @@ next:                   while (r.next()) {
                           " COORD_OP_SCOPE," +
                           " REMARKS," +
                           " DEPRECATED" +
-                    " FROM [Coordinate_Operation]" +
+                    " FROM \"Coordinate_Operation\"" +
                     " WHERE COORD_OP_CODE = ?", code))
             {
                 while (result.next()) {
@@ -2892,7 +2898,7 @@ next:                   while (r.next()) {
                     
opProperties.put(CoordinateOperation.OPERATION_VERSION_KEY, version);
                     if (!Double.isNaN(accuracy)) {
                         
opProperties.put(CoordinateOperation.COORDINATE_OPERATION_ACCURACY_KEY,
-                                PositionalAccuracyConstant.create(accuracy));
+                                         
PositionalAccuracyConstant.create(accuracy));
                     }
                     /*
                      * Creates the operation. Conversions should be the only 
operations allowed to have
@@ -2912,10 +2918,10 @@ next:                   while (r.next()) {
                          */
                         result.close();
                         opProperties = new HashMap<>(opProperties);         // 
Because this class uses a shared map.
-                        final List<String> codes = new ArrayList<>();
+                        final var codes = new ArrayList<String>();
                         try (ResultSet cr = executeQuery("Coordinate_Operation 
Path",
                                 "SELECT SINGLE_OPERATION_CODE" +
-                                 " FROM [Coordinate_Operation Path]" +
+                                 " FROM \"Coordinate_Operation Path\"" +
                                 " WHERE (CONCAT_OPERATION_CODE = ?)" +
                                 " ORDER BY OP_PATH_STEP", epsg))
                         {
@@ -2923,7 +2929,7 @@ next:                   while (r.next()) {
                                 codes.add(getString(code, cr, 1));
                             }
                         }
-                        final CoordinateOperation[] operations = new 
CoordinateOperation[codes.size()];
+                        final var operations = new 
CoordinateOperation[codes.size()];
                         ensureNoCycle(CoordinateOperation.class, epsg);
                         try {
                             for (int i=0; i<operations.length; i++) {
@@ -3020,7 +3026,7 @@ next:                   while (r.next()) {
         ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
         ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
         final String label = sourceCRS + " ⇨ " + targetCRS;
-        final CoordinateOperationSet set = new CoordinateOperationSet(owner);
+        final var set = new CoordinateOperationSet(owner);
         try {
             final int[] pair = toPrimaryKeys(null, null, null, sourceCRS, 
targetCRS);
             boolean searchTransformations = false;
@@ -3034,8 +3040,8 @@ next:                   while (r.next()) {
                 if (searchTransformations) {
                     key = "TransformationFromCRS";
                     sql = "SELECT COORD_OP_CODE" +
-                          " FROM [Coordinate_Operation] AS CO" +
-                          " JOIN [Area] ON AREA_OF_USE_CODE = AREA_CODE" +
+                          " FROM \"Coordinate_Operation\" AS CO" +
+                          " JOIN \"Area\" ON AREA_OF_USE_CODE = AREA_CODE" +
                           " WHERE CO.DEPRECATED=0" +   // Do not put spaces 
around "=" - SQLTranslator searches for this exact match.
                             " AND SOURCE_CRS_CODE = ?" +
                             " AND TARGET_CRS_CODE = ?" +
@@ -3046,7 +3052,7 @@ next:                   while (r.next()) {
                 } else {
                     key = "ConversionFromCRS";
                     sql = "SELECT PROJECTION_CONV_CODE" +
-                          " FROM [Coordinate Reference System]" +
+                          " FROM \"Coordinate Reference System\"" +
                           " WHERE SOURCE_GEOGCRS_CODE = ?" +
                             " AND COORD_REF_SYS_CODE = ?";
                 }
@@ -3123,11 +3129,11 @@ next:                   while (r.next()) {
                     unexpectedException("sort", e);
                     continue;
                 }
-                // Note: "OBJECT_TABLE_NAME=?" is handled in a special way by 
SQLTranslator.
                 try (ResultSet result = executeMetadataQuery("Supersession",
-                        "SELECT SUPERSEDED_BY FROM [Supersession]" +
+                        "SELECT SUPERSEDED_BY FROM \"Supersession\"" +
                         " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?" +
-                        " ORDER BY SUPERSESSION_YEAR DESC", table, code))
+                        " ORDER BY SUPERSESSION_YEAR DESC",
+                        translator.toActualTableName(table), code))
                 {
                     while (result.next()) {
                         final String replacement = result.getString(1);
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 9fdc0cf6d4..fd88b10996 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
@@ -161,8 +161,12 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
     private final InstallationScriptProvider scriptProvider;
 
     /**
-     * The translator from the SQL statements using MS-Access dialect to SQL 
statements using the dialect
-     * of the actual database. If null, will be created when first needed.
+     * The translator from the <abbr>SQL</abbr> statements hard-coded in 
{@link EPSGDataAccess}
+     * to <abbr>SQL</abbr> statements compatible with the actual 
<abbr>EPSG</abbr> database.
+     * This translator may also change the schema and table names used in the 
queries in the
+     * actual database uses different names.
+     *
+     * <p>If {@code null}, a default translator will be created when first 
needed.</p>
      */
     private volatile SQLTranslator translator;
 
@@ -507,10 +511,10 @@ public class EPSGFactory extends 
ConcurrentAuthorityFactory<EPSGDataAccess> impl
      * by {@code new MyDataAccessSubclass(…)}.
      *
      * @param  connection  a connection to the EPSG database.
-     * @param  translator  the translator from the SQL statements using 
MS-Access dialect to SQL statements
-     *                     using the dialect of the actual database.
+     * @param  translator  translator from the <abbr>SQL</abbr> statements 
hard-coded in {@link EPSGDataAccess}
+     *                     to <abbr>SQL</abbr> statements compatible with the 
actual <abbr>EPSG</abbr> database.
      * @return Data Access Object (DAO) to use in {@code createFoo(String)} 
methods.
-     * @throws SQLException if a problem with the database has been detected.
+     * @throws SQLException if an error occurred with the database connection.
      *
      * @see EPSGDataAccess#EPSGDataAccess(EPSGFactory, Connection, 
SQLTranslator)
      */
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 b577ab1676..7f9e451649 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
@@ -91,8 +91,9 @@ final class EPSGInstaller extends ScriptRunner {
     }
 
     /**
-     * Creates immediately a schema of the given name in the database and 
remember that the
-     * {@code "epsg_"} prefix in table names will need to be replaced by path 
to that schema.
+     * Creates immediately a schema of the given name in the database.
+     * The {@code "epsg_"} prefix in table names or the {@code "epsg"}
+     * schema name will be replaced by the given schema name.
      *
      * <p>This method should be invoked only once. It does nothing if the 
database does not supports schema.</p>
      *
@@ -103,17 +104,22 @@ final class EPSGInstaller extends ScriptRunner {
     public void setSchema(final String schema) throws SQLException, 
IOException {
         if (isSchemaSupported) {
             /*
-             * Creates the schema on the database. We do that before to setup 
the 'toSchema' map, while the map still null.
+             * Creates the schema on the database.
              * Note that we do not quote the schema name, which is a somewhat 
arbitrary choice.
              */
-            execute(new StringBuilder("CREATE SCHEMA 
").append(identifierQuote).append(schema).append(identifierQuote));
+            final var sb = new StringBuilder(40);
+            execute(sb.append("CREATE SCHEMA 
").append(identifierQuote).append(schema).append(identifierQuote));
             if (isGrantOnSchemaSupported) {
-                execute(new StringBuilder("GRANT USAGE ON SCHEMA ")
+                sb.setLength(0);
+                execute(sb.append("GRANT USAGE ON SCHEMA ")
                         
.append(identifierQuote).append(schema).append(identifierQuote).append(" TO 
").append(PUBLIC));
             }
             /*
-             * Mapping from the table names used in the SQL scripts to the 
original names used in the MS-Access database.
+             * Mapping from the table names used in the SQL scripts to the 
names used in `EPSGDataAccess`.
+             * Those names are the ones that were used in the original EPSG 
dataset in MS-Access database.
              * We use those original names because they are easier to read 
than the names in SQL scripts.
+             *
+             * TODO: move to 
org.apache.sis.referencing.factory.sql.epsg.DataScriptFormatter.
              */
             addReplacement(SQLTranslator.TABLE_PREFIX + "alias",               
       "Alias");
             addReplacement(SQLTranslator.TABLE_PREFIX + "area",                
       "Area");
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/SQLTranslator.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/SQLTranslator.java
index d4f4953eb8..27f95c2ec2 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/SQLTranslator.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/SQLTranslator.java
@@ -17,61 +17,56 @@
 package org.apache.sis.referencing.factory.sql;
 
 import java.util.Map;
-import java.util.HashMap;
 import java.util.Locale;
 import java.util.function.Function;
 import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Types;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.OptionalCandidate;
+import org.apache.sis.util.StringBuilders;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.privy.Constants;
-import static org.apache.sis.util.privy.Strings.isNullOrEmpty;
 import org.apache.sis.metadata.sql.privy.Reflection;
 import org.apache.sis.metadata.sql.privy.SQLUtilities;
 import org.apache.sis.referencing.internal.Resources;
 
 
 /**
- * Converts the SQL statements from MS-Access dialect to standard SQL. The 
{@link #apply(String)} method
- * is invoked when a new {@link java.sql.PreparedStatement} is about to be 
created from a SQL string.
- * Since the <a href="https://epsg.org/";>EPSG dataset</a> is available 
primarily in MS-Access format,
- * the original SQL statements are formatted using a dialect specific to that 
particular database software.
- * If the actual EPSG dataset to query is hosted on another database product, 
then the SQL query needs to be
- * adapted to the target database dialect before to be executed.
- *
- * <h2>Example</h2>
- * SQL statements for an EPSG dataset hosted on the <i>PostgreSQL</i> database 
need to have their brackets
- * ({@code '['} and {@code ']'}) replaced by the quote character ({@code '"'}) 
before to be sent to the database
- * driver. Furthermore, table names may be different. So the following 
MS-Access query:
+ * Adapter of <abbr>SQL</abbr> statements for variations in syntax and table 
names.
+ * The {@link #apply(String)} method is invoked when a new {@link 
PreparedStatement}
+ * is about to be created from a <abbr>SQL</abbr> string.
+ * This class allows {@link EPSGFactory} to accept some variants of table 
names.
+ * For example, the following <abbr>SQL</abbr> query:
  *
  * <ul>
- *   <li>{@code SELECT * FROM [Coordinate Reference System]}</li>
+ *   <li>{@code SELECT * FROM "Coordinate Reference System"}</li>
  * </ul>
  *
- * needs to be converted to one of the following possibilities for a 
PostgreSQL database
- * (the reason for those multiple choices will be discussed later):
+ * may be converted to one of the following possibilities:
  *
  * <ul>
- *   <li>{@code SELECT * FROM "Coordinate Reference System"}</li>
- *   <li>{@code SELECT * FROM epsg_coordinatereferencesystem} (in the default 
schema)</li>
- *   <li>{@code SELECT * FROM epsg.coordinatereferencesystem} (in the {@code 
"epsg"} schema)</li>
- *   <li>{@code SELECT * FROM epsg."Coordinate Reference System"}</li>
+ *   <li>{@code SELECT * FROM "Coordinate Reference System"} (no change)</li>
+ *   <li>{@code SELECT * FROM coordinatereferencesystem}</li>
+ *   <li>{@code SELECT * FROM epsg_coordinatereferencesystem}</li>
  * </ul>
  *
- * <h2>ANSI SQL</h2>
- * In addition to the file in MS-Access format, EPSG also provides the dataset 
as SQL files for PostgreSQL,
- * MySQL and Oracle databases. Those SQL files are used as both <i>Data 
Description Language</i> (DDL)
- * and <i>Data Manipulation Language</i> (DML).
- * But the table names and some column names in those scripts differ from the 
ones used in the MS-Access database.
- * The following table summarizes the name changes:
+ * The mixed-case variant is used in the dataset distributed by 
<abbr>EPSG</abbr> in the MS-Access format,
+ * while the lower-case variant is used in the <abbr>SQL</abbr> scripts 
distributed by <abbr>EPSG</abbr>.
+ * By default, this class auto-detects which database schema contains the 
<abbr>EPSG</abbr> tables
+ * and whether the database uses the lower-case or mixed-case variant of table 
names.
+ * It is legal to use the mixed-case variant in a PostgreSQL database (for 
example)
+ * even if <abbr>EPSG</abbr> distributes the PosthreSQL scripts in lower-case.
+ * The following table gives the mapping between the two variants accepted by 
{@link EPSGFactory}:
  *
  * <table class="sis">
  *   <caption>Table and column names</caption>
- *   <tr><th>Element</th><th>Name in MS-Access database</th>                   
 <th>Name in SQL scripts</th></tr>
+ *   <tr><th>Element</th><th>Name in MS-Access database</th>                   
 <th>Name in <abbr>SQL</abbr> scripts</th></tr>
  *   <tr><td>Table</td>  <td>{@code Alias}</td>                                
 <td>{@code epsg_alias}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Area}</td>                                 
 <td>{@code epsg_area}</td></tr>
+ *   <tr><td>Table</td>  <td>{@code Change}</td>                               
 <td>{@code epsg_change}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Coordinate Axis}</td>                      
 <td>{@code epsg_coordinateaxis}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Coordinate Axis Name}</td>                 
 <td>{@code epsg_coordinateaxisname}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Coordinate_Operation}</td>                 
 <td>{@code epsg_coordoperation}</td></tr>
@@ -83,18 +78,16 @@ import org.apache.sis.referencing.internal.Resources;
  *   <tr><td>Table</td>  <td>{@code Coordinate Reference System}</td>          
 <td>{@code epsg_coordinatereferencesystem}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Coordinate System}</td>                    
 <td>{@code epsg_coordinatesystem}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Datum}</td>                                
 <td>{@code epsg_datum}</td></tr>
+ *   <tr><td>Table</td>  <td>{@code Deprecation}</td>                          
 <td>{@code epsg_deprecation}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Ellipsoid}</td>                            
 <td>{@code epsg_ellipsoid}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Naming System}</td>                        
 <td>{@code epsg_namingsystem}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Prime Meridian}</td>                       
 <td>{@code epsg_primemeridian}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Supersession}</td>                         
 <td>{@code epsg_supersession}</td></tr>
  *   <tr><td>Table</td>  <td>{@code Unit of Measure}</td>                      
 <td>{@code epsg_unitofmeasure}</td></tr>
+ *   <tr><td>Table</td>  <td>{@code Version History}</td>                      
 <td>{@code epsg_versionhistory}</td></tr>
  *   <tr><td>Column</td> <td>{@code ORDER}</td>                                
 <td>{@code coord_axis_order}</td></tr>
  * </table>
  *
- * By default this class auto-detects the schema that contains the EPSG tables 
and whether the table names are
- * the ones used by EPSG in the MS-Access version or the PostgreSQL, MySQL or 
Oracle version of the database.
- * Consequently, it is legal to use the MS-Access table names, which are more 
readable, in a PostgreSQL database.
- *
  * <h2>Thread safety</h2>
  * All {@code SQLTranslator} instances given to the {@link EPSGFactory} 
constructor
  * <strong>shall</strong> be immutable and thread-safe.
@@ -103,32 +96,34 @@ import org.apache.sis.referencing.internal.Resources;
  * @author  Martin Desruisseaux (IRD)
  * @author  Didier Richard (IGN)
  * @author  John Grange
- * @version 1.0
+ * @version 1.5
  * @since   0.7
  */
 public class SQLTranslator implements Function<String,String> {
     /**
-     * Table names used as "sentinel value" for detecting the presence of an 
EPSG database.
-     * This array lists different possible names for the same table. The first 
entry must be
-     * the MS-Access name. Other names may be in any order. They will be tried 
in reverse order.
+     * The prefix in table names. The SQL scripts are provided by EPSG with 
this prefix in front of all table names.
+     * SIS rather uses a modified version of those SQL scripts which creates 
the tables in an "EPSG" database schema.
+     * But we still need to check for existence of this prefix in case someone 
used the original SQL scripts.
+     *
+     * @see #usePrefixedTableNames
      */
-    private static final String[] SENTINEL = {
-        "Coordinate Reference System",
-        "coordinatereferencesystem",
-        "epsg_coordinatereferencesystem"
-    };
+    static final String TABLE_PREFIX = "epsg_";
 
     /**
-     * Index of the {@link #SENTINEL} element which is in mixed case. No other 
element should be in mixed case.
+     * Table names used as "sentinel value" for detecting the presence of an 
<abbr>EPSG</abbr> database.
+     * This array lists different names that may be used for the same table. 
The names will be tested in
+     * declaration order.
      */
-    private static final int MIXED_CASE = 0;
+    private static final String[] SENTINEL = {
+        TABLE_PREFIX + "coordinatereferencesystem",
+        "Coordinate Reference System",      // The index of this entry must be 
declared in `MIXED_CASE`.
+        "coordinatereferencesystem"
+    };
 
     /**
-     * The prefix in table names. The SQL scripts are provided by EPSG with 
this prefix in front of all table names.
-     * SIS rather uses a modified version of those SQL scripts which creates 
the tables in an "EPSG" database schema.
-     * But we still need to check for existence of this prefix in case someone 
used the original SQL scripts.
+     * Index of the {@link #SENTINEL} element which is in mixed case. No other 
element should be in mixed case.
      */
-    static final String TABLE_PREFIX = "epsg_";
+    private static final int MIXED_CASE = 1;
 
     /**
      * The columns that may be of {@code BOOLEAN} type instead of {@code 
SMALLINT}.
@@ -140,22 +135,19 @@ public class SQLTranslator implements 
Function<String,String> {
     };
 
     /**
-     * The column where {@code VARCHAR} value may need to be casted to an 
enumeration.
-     * With PostgreSQL, only columns in the {@code WHERE} part of the SQL 
statement needs
-     * an explicit cast; the columns in the {@code SELECT} part are implicitly 
casted.
+     * The column where {@code VARCHAR} value may need to be cast to an 
enumeration.
+     * With PostgreSQL, only columns in the {@code WHERE} part of the 
<abbr>SQL</abbr> statement
+     * needs an explicit cast, as the columns in the {@code SELECT} part are 
implicitly cast.
      */
     private static final String ENUMERATION_COLUMN = "OBJECT_TABLE_NAME";      
     // In "Alias" table.
 
     /**
      * The name of the catalog that contains the EPSG tables, or {@code null} 
or an empty string.
      * <ul>
-     *   <li>The {@code ""} value retrieves the EPSG schema without a 
catalog.</li>
+     *   <li>The {@code ""} value retrieves the <abbr>EPSG</abbr> schema 
without a catalog.</li>
      *   <li>The {@code null} value means that the catalog name should not be 
used to narrow the search.</li>
      * </ul>
      *
-     * <p><b>Consider this field as final.</b> This field is non-final only 
for construction convenience,
-     * or for updating after the {@link EPSGInstaller} class created the 
database.</p>
-     *
      * @see #getCatalog()
      */
     private String catalog;
@@ -164,50 +156,61 @@ public class SQLTranslator implements 
Function<String,String> {
      * The name of the schema that contains the EPSG tables, or {@code null} 
or an empty string.
      * <ul>
      *   <li>The {@code ""} value retrieves the EPSG tables without a schema.
-     *       In such case, table names are prefixed by {@value 
#TABLE_PREFIX}.</li>
+     *       In such case, table names are typically prefixed by {@value 
#TABLE_PREFIX}.</li>
      *   <li>The {@code null} value means that the schema name should not be 
used to narrow the search.
-     *       In such case, {@code SQLTranslator} will tries to automatically 
detect the schema.</li>
+     *       In such case, {@code SQLTranslator} will try to automatically 
detect the schema.</li>
      * </ul>
      *
-     * <b>Consider this field as final.</b> This field is non-final only for 
construction convenience,
-     * or for updating after the {@link EPSGInstaller} class created the 
database.
+     * Note that the <abbr>SQL</abbr> scripts distributed by <abbr>EPSG</abbr> 
do not use schema.
+     * Instead, <abbr>EPSG</abbr> puts an {@value #TABLE_PREFIX} prefix in 
front of every table names.
+     * The {@link #usePrefixedTableNames} flag tells whether it is the case 
for the current database.
+     * The two approaches (schema or prefix) are redundant, but it is okay to 
use both of them anyway.
      *
      * @see #getSchema()
+     * @see #usePrefixedTableNames
      */
     private String schema;
 
     /**
-     * Whether the table names are prefixed by {@value #TABLE_PREFIX}. When 
installed by Apache SIS,
-     * the table names are not prefixed if the tables are stored in a schema. 
However, the dataset may
-     * have been installed manually by users following different rules.
+     * Whether the table names are prefixed by {@value #TABLE_PREFIX}. The 
<abbr>EPSG</abbr> geodetic dataset
+     * in the {@code org.apache.sis.referencing.epsg} module replaces that 
prefix by the {@code "epsg"} schema.
+     * However, if the dataset has been installed manually by the user, then 
the table name prefix is present.
+     *
+     * @see #TABLE_PREFIX
+     * @see #schema
+     */
+    private boolean usePrefixedTableNames;
+
+    /**
+     * {@code true} if this class uses mixed-case convention for table names.
+     * In such case, the table names will need to be quoted using the {@link 
#quote} character.
      */
-    private boolean isPrefixed;
+    private boolean useMixedCaseTableNames;
 
     /**
-     * Mapping from words used in the MS-Access database to words used in the 
ANSI versions of EPSG databases.
-     * A word may be a table or a column name, or a part of it. A table name 
may consist of many words separated
-     * by spaces. This map does not list all tables used in EPSG schema, but 
only the ones that cannot be mapped
+     * Mapping from mixed-case "word" used by {@link EPSGDataAccess} to the 
words actually used by the database.
+     * A word may be a table name or a part of it. A table name may consist of 
many words separated by spaces.
+     * This map does not list all tables used in <abbr>EPSG</abbr> schema, but 
only the ones that cannot be mapped
      * by more generic code (e.g. by replacing spaces by '_').
      *
-     * <p>The keys are the names in the MS-Access database, and the values are 
the names in the SQL scripts.
-     * By convention, all column names in keys are in upper-case while table 
names are in mixed-case characters.</p>
+     * <p>The keys are names that are hard-coded in the <abbr>SQL</abbr> 
statements of {@link EPSGDataAccess} class,
+     * and values are the names used in the <abbr>EPSG</abbr> database on 
which {@link EPSGDataAccess} is connected.
+     * By convention, all column names are in upper-case while table names are 
in mixed-case characters.</p>
      */
-    private final Map<String,String> accessToAnsi;
+    private Map<String,String> tableRenaming;
 
     /**
-     * {@code true} if this class needs to quote table names. This quoting 
should be done only if the database
-     * uses the MS-Access table names, even if we are targeting a PostgreSQL, 
MySQL or Oracle database.
-     *
-     * <p><b>Consider this field as final.</b> This field is non-final only 
for construction convenience,
-     * or for updating after the {@link EPSGInstaller} class created the 
database.</p>
+     * Mapping from column names used by {@link EPSGDataAccess} to the names 
actually used by the database.
+     * The {@code COORD_AXIS_ORDER} column may be {@code ORDER} in the 
MS-Access database.
+     * This map is rarely non-empty.
      */
-    private boolean quoteTableNames;
+    private Map<String,String> columnRenaming;
 
     /**
      * The characters used for quoting identifiers, or a whitespace if none.
      * This information is provided by {@link 
DatabaseMetaData#getIdentifierQuoteString()}.
      */
-    private final String quote;
+    private final String identifierQuote;
 
     /**
      * Non-null if the {@value #ENUMERATION_COLUMN} column in {@code "Alias"} 
table uses enumeration instead
@@ -233,9 +236,15 @@ public class SQLTranslator implements 
Function<String,String> {
     private boolean isTableFound;
 
     /**
-     * Creates a new SQL translator for the database described by the given 
metadata.
+     * Whether the <abbr>SQL</abbr> queries hard-coded in {@link 
EPSGDataAccess} can be used verbatim
+     * with the actual database. This is {@code true} if this translator 
applies no change at all.
+     */
+    private boolean sameQueries;
+
+    /**
+     * Creates a new <abbr>SQL</abbr> translator for the database described by 
the given metadata.
      * This constructor detects automatically the dialect: the characters to 
use for quoting identifiers,
-     * and whether the table names are the ones used in the MS-Access database 
or in the SQL scripts.
+     * and whether the <abbr>EPSG</abbr> table names uses the mixed-case or 
lower-case convention.
      *
      * <p>If the given catalog or schema name is non-null, then the 
{@linkplain DatabaseMetaData#getTables
      * search for EPSG tables} will be restricted to the catalog or schema of 
that name.
@@ -248,8 +257,7 @@ public class SQLTranslator implements 
Function<String,String> {
      * @throws SQLException if an error occurred while querying the database 
metadata.
      */
     public SQLTranslator(final DatabaseMetaData md, final String catalog, 
final String schema) throws SQLException {
-        quote = md.getIdentifierQuoteString().trim();
-        accessToAnsi = new HashMap<>(4);
+        identifierQuote = md.getIdentifierQuoteString().trim();
         this.catalog = catalog;
         this.schema  = schema;
         setup(md);
@@ -259,29 +267,30 @@ public class SQLTranslator implements 
Function<String,String> {
      * Sets the value of all non-final fields. This method performs two steps:
      *
      * <ol class="verbose">
-     *   <li>Finds the schema that seems to contain the EPSG tables. If there 
is more than one schema containing the
+     *   <li>Find the schema that seems to contain the EPSG tables. If there 
is more than one schema containing the
      *       tables, gives precedence to the schema named "EPSG" if one is 
found. If there is no schema named "EPSG",
-     *       takes an arbitrary schema. It may be the empty string if the 
tables are not contained in a schema.</li>
+     *       take an arbitrary schema. It may be the empty string if the 
tables are not contained in a schema.</li>
      *
-     *   <li>Fills the {@link #accessToAnsi} map. That map translates the 
table and column names used in the SQL
-     *       statements into the names used by the database. Two conventions 
are understood: the names used in
-     *       the MS-Access database or the names used in the SQL scripts. Both 
of them are distributed by EPSG.</li>
+     *   <li>Fill the {@link #tableRenaming} and {@link #columnRenaming} maps. 
These maps translate table
+     *       and column names used in the <abbr>SQL</abbr> statements into the 
names used by the database.
+     *       Two conventions are understood: the names used in the MS-Access 
database or the names used
+     *       in the <abbr>SQL</abbr> scripts. Both of them are distributed by 
<abbr>EPSG</abbr>.</li>
      * </ol>
      */
     final void setup(final DatabaseMetaData md) throws SQLException {
         final boolean toUpperCase = md.storesUpperCaseIdentifiers();
         final String escape = md.getSearchStringEscape();
         String schemaPattern = SQLUtilities.escape(schema, escape);
-        for (int i = SENTINEL.length; --i >= 0;) {
+        for (int i=0; i<SENTINEL.length; i++) {
             String table = SENTINEL[i];
             if (toUpperCase && i != MIXED_CASE) {
                 table = table.toUpperCase(Locale.US);
             }
             try (ResultSet result = md.getTables(catalog, schemaPattern, 
table, null)) {
                 if (result.next()) {
-                    isTableFound    = true;
-                    isPrefixed      = table.startsWith(TABLE_PREFIX);
-                    quoteTableNames = (i == MIXED_CASE);
+                    isTableFound = true;
+                    usePrefixedTableNames  = table.startsWith(TABLE_PREFIX);
+                    useMixedCaseTableNames = (i == MIXED_CASE);
                     do {
                         catalog = result.getString(Reflection.TABLE_CAT);
                         schema  = result.getString(Reflection.TABLE_SCHEM);
@@ -292,27 +301,28 @@ public class SQLTranslator implements 
Function<String,String> {
                 }
             }
         }
+        tableRenaming  = Map.of();
+        columnRenaming = Map.of();
+        if (!isTableFound) {
+            return;
+        }
         /*
-         * At this point the catalog and schema have been found or confirmed, 
or are still null
-         * if we did not found them. Now fill the 'accessToAnsi' map.
+         * At this point, the catalog and schema have been found or have been 
confirmed,
+         * or are still null if we did not found the EPSG table used as a 
sentinel value.
          */
-        boolean translateColumns = true;
-        accessToAnsi.clear();
-        if (quoteTableNames) {
-            /*
-             * MS-Access database uses a column named "ORDER" in the 
"Coordinate Axis" table.
-             * This column has been renamed "coord_axis_order" in DLL scripts.
-             * We need to check which name our current database uses.
-             */
-            try (ResultSet result = md.getColumns(catalog, schemaPattern, 
"Coordinate Axis", "ORDER")) {
-                translateColumns = !result.next();
-            }
-        } else {
-            accessToAnsi.put("Coordinate_Operation", "coordoperation");
-            accessToAnsi.put("Parameter", "param");
+        if (!useMixedCaseTableNames) {
+            tableRenaming = Map.of("Coordinate_Operation", "coordoperation",
+                                   "Parameter",            "param");
         }
-        if (translateColumns) {
-            accessToAnsi.put("ORDER", "coord_axis_order");
+        /*
+         * MS-Access database uses a column named "ORDER" in the "Coordinate 
Axis" table.
+         * This column has been renamed "coord_axis_order" in DLL scripts.
+         * We need to check which name our current database uses.
+         */
+        try (ResultSet result = md.getColumns(catalog, schemaPattern, 
toActualTableName("Coordinate Axis"), "ORDER")) {
+            if (result.next()) {
+                columnRenaming = Map.of("COORD_AXIS_ORDER", "ORDER");
+            }
         }
         /*
          * Detect if the database uses boolean types where applicable.
@@ -324,7 +334,7 @@ public class SQLTranslator implements 
Function<String,String> {
             deprecated  =  deprecated.toLowerCase(Locale.US);
             objectTable = objectTable.toLowerCase(Locale.US);
         }
-        final String tablePattern = isPrefixed ? 
SQLUtilities.escape(TABLE_PREFIX, escape) + '%' : null;
+        final String tablePattern = usePrefixedTableNames ? 
SQLUtilities.escape(TABLE_PREFIX, escape) + '%' : null;
         try (ResultSet result = md.getColumns(catalog, schemaPattern, 
tablePattern, deprecated)) {
             while (result.next()) {
                 if 
(CharSequences.endsWith(result.getString(Reflection.TABLE_NAME), "Datum", 
true)) {
@@ -335,8 +345,8 @@ public class SQLTranslator implements 
Function<String,String> {
             }
         }
         /*
-         * Detect if the table use enumeration (on PostgreSQL database) 
instead of VARCHAR.
-         * Enumerations appear in various tables, but is used in WHERE clause 
in the Alias table.
+         * Detect if the tables use enumeration (on PostgreSQL database) 
instead of VARCHAR.
+         * Enumerations appear in various tables, including in a WHERE clause 
for the Alias table.
          */
         try (ResultSet result = md.getColumns(catalog, schemaPattern, 
tablePattern, objectTable)) {
             while (result.next()) {
@@ -349,6 +359,11 @@ public class SQLTranslator implements 
Function<String,String> {
                 }
             }
         }
+        sameQueries = (tableNameEnum == null)
+                && tableRenaming.isEmpty()
+                && columnRenaming.isEmpty()
+                && "\"".equals(identifierQuote)
+                && !useBoolean;
     }
 
     /**
@@ -359,6 +374,7 @@ public class SQLTranslator implements 
Function<String,String> {
      *
      * @return the catalog that contains the EPSG schema, or {@code null}.
      */
+    @OptionalCandidate
     public String getCatalog() {
         return catalog;
     }
@@ -371,6 +387,7 @@ public class SQLTranslator implements 
Function<String,String> {
      *
      * @return the schema that contains the EPSG tables, or {@code null}.
      */
+    @OptionalCandidate
     public String getSchema() {
         return schema;
     }
@@ -409,60 +426,94 @@ public class SQLTranslator implements 
Function<String,String> {
     }
 
     /**
-     * Adapts the given SQL statement from the original MS-Access dialect to 
the dialect of the target database.
-     * Table and column names may also be replaced.
+     * Converts a mixed-case table name to the convention used in the database.
+     * The names of the tables for the two conventions are listed in a table 
in the Javadoc of this class.
+     * The rreturned string does not include the identifier quotes.
+     *
+     * @param  name  the mixed-case table name.
+     * @return the name converted to the convention used by the database.
+     * @since 1.5
+     */
+    public final String toActualTableName(String name) {
+        if (useMixedCaseTableNames) {
+            return name;
+        }
+        final var buffer = new StringBuilder(name.length() + 5);
+        toActualTableName(name, buffer);
+        return buffer.toString().toLowerCase(Locale.US);
+    }
+
+    /**
+     * Appends the table name in the given buffer, converted to the convention 
used in the database.
+     * Identifier quotes are added when mixed-case is used. Otherwise, the 
identifier may not be in
+     * the right lower/upper case. But when there is no identifier quotes, the 
database should convert
+     * to* whatever convention it uses.
+     */
+    private void toActualTableName(final String name, final StringBuilder 
buffer) {
+        if (useMixedCaseTableNames) {
+            
buffer.append(identifierQuote).append(name).append(identifierQuote);
+        } else {
+            if (usePrefixedTableNames) {
+                buffer.append(TABLE_PREFIX);
+            }
+            for (final String word : name.split("\\s")) {
+                buffer.append(tableRenaming.getOrDefault(word, word));
+            }
+            // Ignore lower/upper case.
+        }
+    }
+
+    /**
+     * Adapts the given <abbr>SQL</abbr> statement from the mixed-case 
convention to the convention used by
+     * the target database. The mixed-case convention is used by {@link 
EPSGDataAccess} hard-coded queries.
+     * This method can replace the schema and table names, and sometime some 
<abbr>SQL</abbr> keywords,
+     * for complying with the expectation of the target database.
      *
-     * @param  sql  the statement in MS-Access dialect.
-     * @return the SQL statement adapted to the dialect of the target database.
+     * @param  sql  a <abbr>SQL</abbr> statement with table names in 
mixed-case convention.
+     * @return the given statement adapted to the expectation of the target 
database.
      */
     @Override
     public String apply(final String sql) {
-        if (quote.isEmpty() && accessToAnsi.isEmpty() && isNullOrEmpty(schema) 
&& isNullOrEmpty(catalog)) {
-            return sql;
+        if (sameQueries) {
+            return sql;     // Shortcut when there is nothing to change.
         }
-        final StringBuilder ansi = new StringBuilder(sql.length() + 16);
-        int start, end = 0;
-        while ((start = sql.indexOf('[', end)) >= 0) {
-            /*
-             * Append every characters since the end of the last processed 
table/column name,
-             * or since the beginning of the SQL statement if we are in the 
first iteration.
-             * Then find the end of the new table/column name to process in 
this iteration.
-             */
-            ansi.append(sql, end, start);
-            if ((end = sql.indexOf(']', ++start)) < 0) {
-                throw new IllegalArgumentException(Errors.format(
-                        Errors.Keys.MissingCharacterInElement_2, 
sql.substring(start), ']'));
-            }
-            /*
-             * The name can be a table name or a column name, but only table 
names will be quoted.
-             * EPSG seems to write all column names in upper-case (MS-Access) 
or lower-case (ANSI),
-             * so we will let the database driver selects the case of its 
choice for column names.
-             */
-            final String name = sql.substring(start, end++);
-            if (CharSequences.isUpperCase(name)) {
-                ansi.append(accessToAnsi.getOrDefault(name, name));
-            } else {
-                appendIdentifier(ansi, name);
+        final var buffer = new StringBuilder(sql.length() + 16);
+        int end = 0;
+        if (!(useMixedCaseTableNames && "\"".equals(identifierQuote))) {
+            int start;
+            while ((start = sql.indexOf('"', end)) >= 0) {
+                /*
+                 * Append every characters since the end of the last processed 
table/column name,
+                 * or since the beginning of the SQL statement if we are in 
the first iteration.
+                 * Then find the end of the new table/column name to process 
in this iteration.
+                 */
+                buffer.append(sql, end, start);
+                if ((end = sql.indexOf('"', ++start)) < 0) {
+                    throw new IllegalArgumentException(Errors.format(
+                            Errors.Keys.MissingCharacterInElement_2, 
sql.substring(start), '"'));
+                }
+                toActualTableName(sql.substring(start, end++), buffer);
             }
         }
-        ansi.append(sql, end, sql.length());
+        buffer.append(sql, end, sql.length());
+        columnRenaming.forEach((toSearch, replaceBy) -> 
StringBuilders.replace(buffer, toSearch, replaceBy));
         /*
          * If the database use the BOOLEAN type instead of SMALLINT, replaces 
"deprecated=0' by "deprecated=false".
          */
         if (useBoolean) {
-            int w = ansi.indexOf("WHERE");
+            int w = buffer.indexOf("WHERE");
             if (w >= 0) {
                 w += 5;
                 for (final String field : BOOLEAN_COLUMNS) {
-                    int p = ansi.indexOf(field, w);
+                    int p = buffer.indexOf(field, w);
                     if (p >= 0) {
                         p += field.length();
-                        if (!replaceIfEquals(ansi, p, "=0", "=FALSE") &&
-                            !replaceIfEquals(ansi, p, "<>0", "=TRUE"))
+                        if (!replaceIfEquals(buffer, p, "=0", "=FALSE") &&
+                            !replaceIfEquals(buffer, p, "<>0", "=TRUE"))
                         {
                             // Remove "ABS" in "ABS(DEPRECATED)" or 
"ABS(CO.DEPRECATED)".
-                            if ((p = ansi.lastIndexOf("(", p)) > w) {
-                                replaceIfEquals(ansi, p-3, "ABS", "");
+                            if ((p = buffer.lastIndexOf("(", p)) > w) {
+                                replaceIfEquals(buffer, p-3, "ABS", "");
                             }
                         }
                     }
@@ -474,49 +525,23 @@ public class SQLTranslator implements 
Function<String,String> {
          * The enumeration type is typically "EPSG"."Table Name".
          */
         if (tableNameEnum != null) {
-            int w = ansi.lastIndexOf(ENUMERATION_COLUMN + "=?");
+            int w = buffer.lastIndexOf(ENUMERATION_COLUMN + "=?");
             if (w >= 0) {
                 w += ENUMERATION_COLUMN.length() + 1;
-                ansi.replace(w, w+1, "CAST(? AS " + tableNameEnum + ')');
-            }
-        }
-        return ansi.toString();
-    }
-
-    /**
-     * Appends the given identifier in the given buffer, between quotes and 
prefixed with the schema name.
-     * This is used mostly for appending table names, but can also be used for 
appending enumeration types.
-     */
-    private void appendIdentifier(final StringBuilder buffer, final String 
identifier) {
-        if (!isNullOrEmpty(catalog)) {
-            buffer.append(quote).append(catalog).append(quote).append('.');
-        }
-        if (!isNullOrEmpty(schema)) {
-            buffer.append(quote).append(schema).append(quote).append('.');
-        }
-        if (quoteTableNames) {
-            buffer.append(quote);
-        }
-        if (isPrefixed) {
-            buffer.append(TABLE_PREFIX);
-        }
-        if (quoteTableNames) {
-            buffer.append(accessToAnsi.getOrDefault(identifier, 
identifier)).append(quote);
-        } else {
-            for (final String word : identifier.split("\\s")) {
-                buffer.append(accessToAnsi.getOrDefault(word, word));
+                buffer.replace(w, w+1, "CAST(? AS " + tableNameEnum + ')');
             }
         }
+        return buffer.toString();
     }
 
     /**
      * Replaces the text at the given position in the buffer if it is equal to 
the {@code expected} text.
      */
-    private static boolean replaceIfEquals(final StringBuilder ansi, final int 
pos,
+    private static boolean replaceIfEquals(final StringBuilder buffer, final 
int pos,
             final String expected, final String replacement)
     {
-        if (CharSequences.regionMatches(ansi, pos, expected)) {
-            ansi.replace(pos, pos + expected.length(), replacement);
+        if (CharSequences.regionMatches(buffer, pos, expected)) {
+            buffer.replace(pos, pos + expected.length(), replacement);
             return true;
         }
         return false;
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 1223b01b5f..f632440ebb 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
@@ -31,29 +31,29 @@ import org.apache.sis.referencing.crs.DefaultGeocentricCRS;
 
 
 /**
- * Information about a specific table. The MS-Access dialect of SQL is assumed;
- * it will be translated into ANSI SQL later by {@link 
SQLTranslator#apply(String)} if needed.
+ * Information about a specific table. This class uses the mixed-case variant 
of the <abbr>EPSG</abbr> table names.
+ * If needed, those names will be converted by {@link 
SQLTranslator#apply(String)} to the actual table names.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  */
 final class TableInfo {
     /**
-     * The {@link EPSG} item used for coordinate reference systems.
+     * The item used for coordinate reference systems.
      */
     static final TableInfo CRS;
 
     /**
-     * The {@link EPSG} item used for datums.
+     * The item used for datums.
      */
     static final TableInfo DATUM;
 
     /**
-     * The {@link EPSG} item used for ellipsoids.
+     * The item used for ellipsoids.
      */
     static final TableInfo ELLIPSOID;
 
     /**
-     * List of tables and columns to test for codes values.
+     * List of tables and columns to test for existence of codes values.
      * Those tables are used by the {@link 
EPSGDataAccess#createObject(String)} method
      * in order to detect which of the following methods should be invoked for 
a given code:
      *
@@ -73,7 +73,7 @@ final class TableInfo {
      */
     static final TableInfo[] EPSG = {
         CRS = new TableInfo(CoordinateReferenceSystem.class,
-                "[Coordinate Reference System]",
+                "\"Coordinate Reference System\"",
                 "COORD_REF_SYS_CODE",
                 "COORD_REF_SYS_NAME",
                 "COORD_REF_SYS_KIND",
@@ -92,7 +92,7 @@ final class TableInfo {
                  */
 
         new TableInfo(CoordinateSystem.class,
-                "[Coordinate System]",
+                "\"Coordinate System\"",
                 "COORD_SYS_CODE",
                 "COORD_SYS_NAME",
                 "COORD_SYS_TYPE",
@@ -105,14 +105,14 @@ final class TableInfo {
                 null),
 
         new TableInfo(CoordinateSystemAxis.class,
-                "[Coordinate Axis] AS CA INNER JOIN [Coordinate Axis Name] AS 
CAN" +
-                                 " ON 
CA.COORD_AXIS_NAME_CODE=CAN.COORD_AXIS_NAME_CODE",
+                "\"Coordinate Axis\" AS CA INNER JOIN \"Coordinate Axis Name\" 
AS CAN " +
+                                    "ON 
CA.COORD_AXIS_NAME_CODE=CAN.COORD_AXIS_NAME_CODE",
                 "COORD_AXIS_CODE",
                 "COORD_AXIS_NAME",
                 null, null, null, null),
 
         DATUM = new TableInfo(Datum.class,
-                "[Datum]",
+                "\"Datum\"",
                 "DATUM_CODE",
                 "DATUM_NAME",
                 "DATUM_TYPE",
@@ -123,19 +123,19 @@ final class TableInfo {
                 null),
 
         ELLIPSOID = new TableInfo(Ellipsoid.class,
-                "[Ellipsoid]",
+                "\"Ellipsoid\"",
                 "ELLIPSOID_CODE",
                 "ELLIPSOID_NAME",
                 null, null, null, null),
 
         new TableInfo(PrimeMeridian.class,
-                "[Prime Meridian]",
+                "\"Prime Meridian\"",
                 "PRIME_MERIDIAN_CODE",
                 "PRIME_MERIDIAN_NAME",
                 null, null, null, null),
 
         new TableInfo(CoordinateOperation.class,
-                "[Coordinate_Operation]",
+                "\"Coordinate_Operation\"",
                 "COORD_OP_CODE",
                 "COORD_OP_NAME",
                 "COORD_OP_TYPE",
@@ -144,31 +144,32 @@ final class TableInfo {
                 "SHOW_OPERATION"),
 
         new TableInfo(OperationMethod.class,
-                "[Coordinate_Operation Method]",
+                "\"Coordinate_Operation Method\"",
                 "COORD_OP_METHOD_CODE",
                 "COORD_OP_METHOD_NAME",
                 null, null, null, null),
 
         new TableInfo(ParameterDescriptor.class,
-                "[Coordinate_Operation Parameter]",
+                "\"Coordinate_Operation Parameter\"",
                 "PARAMETER_CODE",
                 "PARAMETER_NAME",
                 null, null, null, null),
 
         new TableInfo(Unit.class,
-                "[Unit of Measure]",
+                "\"Unit of Measure\"",
                 "UOM_CODE",
                 "UNIT_OF_MEAS_NAME",
                 null, null, null, null),
     };
 
     /**
-     * The class of object to be created.
+     * The class of object to be created (usually a GeoAPI interface).
      */
     final Class<?> type;
 
     /**
-     * The table name for SQL queries. May contains a {@code "JOIN"} clause.
+     * The table name for SQL queries, including schema name and quotes for 
mixed-case names.
+     * May contain a {@code JOIN} clause.
      *
      * @see #unquoted()
      */
@@ -186,8 +187,8 @@ final class TableInfo {
 
     /**
      * Column type for the type (usually with the {@code "_TYPE"} suffix), or 
{@code null}.
-     * {@link EPSGDataAccess} and {@link AuthorityCodes} assumes that values 
in this column
-     * have the maximal length described in the {@value #ENUM_REPLACEMENT} 
statement.
+     * {@link EPSGDataAccess} and {@link AuthorityCodes} assume that values in 
this column
+     * are not longer than the maximal length specified in {@value 
#ENUM_REPLACEMENT}.
      */
     private final String typeColumn;
 
@@ -213,6 +214,15 @@ final class TableInfo {
 
     /**
      * Stores information about a specific table.
+     *
+     * @param type        the class of object to be created (usually a GeoAPI 
interface).
+     * @param table       the table name for SQL queries, including quotes for 
mixed-case names.
+     * @param codeColumn  column name for the code (usually with the {@code 
"_CODE"} suffix).
+     * @param nameColumn  column name for the name (usually with the {@code 
"_NAME"} suffix), or {@code null}.
+     * @param typeColumn  column type for the type (usually with the {@code 
"_TYPE"} suffix), or {@code null}.
+     * @param subTypes    sub-interfaces of {@link #type} to handle, or {@code 
null} if none.
+     * @param typeNames   names of {@code subTypes} in the database, or {@code 
null} if none.
+     * @param showColumn  the column that specify if the object should be 
shown, or {@code null} if none.
      */
     private TableInfo(final Class<?> type,
                       final String table, final String codeColumn, final 
String nameColumn,
@@ -230,32 +240,31 @@ final class TableInfo {
     }
 
     /**
-     * Returns the table name without brackets.
+     * Returns the table name without schema name and without quotes.
      */
     final String unquoted() {
-        return table.substring(1, table.length() - 1);
+        return table.substring(table.indexOf('"') + 1, table.lastIndexOf('"'));
     }
 
     /**
-     * Returns {@code true} if the given table {@code name} matches the {@code 
expected} name.
+     * Returns {@code true} if the given table {@code name} matches the name 
expected by {@code this}.
      * The given {@code 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"}.
      *
-     * <p>The table name should be one of the values enumerated in the {@code 
epsg_table_name} type of the
+     * <p>The table name should be one of the values enumerated in the {@code 
epsg_table_name} types of the
      * {@code EPSG_Prepare.sql} file.</p>
      *
-     * @param  expected  the expected table name (e.g. {@code 
"Coordinate_Operation"}).
-     * @param  name      the actual table name.
+     * @param  name  the table name to test.
      * @return whether the given {@code name} is considered to match the 
expected name.
      */
-    static boolean tableMatches(final String expected, String name) {
+    final boolean tableMatches(String name) {
         if (name == null) {
             return false;
         }
         if (name.startsWith(SQLTranslator.TABLE_PREFIX)) {
             name = name.substring(SQLTranslator.TABLE_PREFIX.length());
         }
-        return CharSequences.isAcronymForWords(name, expected);
+        return CharSequences.isAcronymForWords(name, unquoted());
     }
 
     /**
@@ -288,7 +297,7 @@ final class TableInfo {
      *     WHERE COORD_REF_SYS_KIND LIKE 'geographic%' AND
      *     }
      *
-     * In any case, the caller shall add at least one condition after this 
method call.
+     * The caller shall add at least one condition after this method call.
      *
      * @param  userType  the type specified by the user.
      * @param  buffer    where to append the {@code WHERE} clause.
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 5bf31094cb..bde70bffc3 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,8 +24,8 @@
  *
  *
  * <h2>Connection to the database</h2>
- * By default Apache SIS uses Apache Derby,
- * but the database can also be PostgreSQL or MS-Access.
+ * 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).
  * The database connection is obtained by the first of the following data 
sources which is found:
  *
  * <ol>
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/SignReversalComment.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/SignReversalComment.java
index 68d88099d6..d69cbba856 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/SignReversalComment.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/SignReversalComment.java
@@ -24,8 +24,8 @@ import org.apache.sis.util.AbstractInternationalString;
 
 /**
  * Comments telling whether a parameter value uses the same sign or the 
opposite sign for the inverse operation.
- * Those comments are used for encoding the {@code PARAM_SIGN_REVERSAL} 
boolean value in the
- * {@code [Coordinate_Operation Parameter Usage]} table of the EPSG dataset.
+ * Those comments are used for encoding the {@code PARAM_SIGN_REVERSAL} 
Boolean value in the
+ * {@code "Coordinate_Operation Parameter Usage"} table of the 
<abbr>EPSG</abbr> dataset.
  *
  * <p>This approach may change in any future SIS version.</p>
  *
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
index 1d1dfa0c5b..5605224192 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
@@ -327,12 +327,12 @@ public abstract class AbstractProvider extends 
DefaultOperationMethod implements
      * This is different than the EPSG dataset in two ways:
      *
      * <ul class="verbose">
-     *   <li>EPSG provides an equivalent information in the {@code 
PARAM_SIGN_REVERSAL} column of the
-     *       {@code [Coordinate_Operation Parameter Usage]} table, but on a 
parameter-by-parameter basis
+     *   <li><abbr>EPSG</abbr> provides an equivalent information in the 
{@code PARAM_SIGN_REVERSAL} column
+     *       of the {@code "Coordinate_Operation Parameter Usage"} table, but 
on a parameter-by-parameter basis
      *       instead of for the whole operation (which is probably 
better).</li>
      *
-     *   <li>EPSG provides another information in the {@code REVERSE_OP} 
column of the
-     *       {@code [Coordinate_Operation Method]} table, but this is not 
equivalent to this method because it
+     *   <li><abbr>EPSG</abbr> provides another information in the {@code 
REVERSE_OP} column of the
+     *       {@code "Coordinate_Operation Method"} table, but this is not 
equivalent to this method because it
      *       does not differentiate the map projection methods from 
<em>inverse</em> map projection methods.</li>
      * </ul>
      *
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 9579346e50..6926b7096b 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
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.referencing.factory.sql;
 
-import java.util.Map;
 import java.util.Set;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -87,7 +86,7 @@ public final class EPSGInstallerTest extends TestCaseWithLogs 
{
                 "UPDATE epsg_datum\n" +
                 "SET datum_name = replace(datum_name, CHAR(182), CHAR(10))"));
 
-        // Modified statement with MS-Access table name in a schema.
+        // Modified statement with mixed-case table name in a schema.
         assertTrue(Pattern.matches(EPSGInstaller.REPLACE_STATEMENT,
                 "UPDATE epsg.\"Alias\"\n" +
                 "SET object_table_name = replace(object_table_name, CHR(182), 
CHR(10))"));
@@ -199,7 +198,7 @@ public final class EPSGInstallerTest extends 
TestCaseWithLogs {
     private void createAndTest(final DataSource ds, final 
InstallationScriptProvider scriptProvider)
             throws SQLException, FactoryException
     {
-        final Map<String,Object> properties = new HashMap<>();
+        final var properties = new HashMap<String,Object>();
         assertNull(properties.put("dataSource", ds));
         assertNull(properties.put("scriptProvider", scriptProvider));
         assertEquals(0, countCRSTables(ds), "Should not contain EPSG tables 
before we created them.");
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/TableInfoTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/TableInfoTest.java
index 2094ed22fa..259ec10a91 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/TableInfoTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/TableInfoTest.java
@@ -35,11 +35,12 @@ public final class TableInfoTest extends TestCase {
     }
 
     /**
-     * Tests {@link TableInfo#tableMatches(String, String)}.
+     * Tests {@link TableInfo#tableMatches(String)}.
      */
     @Test
     public void testTableMatches() {
-        assertTrue(TableInfo.tableMatches("Coordinate_Operation",          
"epsg_coordoperation"));
-        assertTrue(TableInfo.tableMatches("[Coordinate Reference System]", 
"epsg_coordinatereferencesystem"));
+        assertTrue(TableInfo.DATUM    .tableMatches("epsg_datum"));
+        assertTrue(TableInfo.ELLIPSOID.tableMatches("epsg_ellipsoid"));
+        assertTrue(TableInfo.CRS      
.tableMatches("epsg_coordinatereferencesystem"));
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/CharSequencesTest.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/CharSequencesTest.java
index b019636934..baf59f7d9c 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/CharSequencesTest.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/CharSequencesTest.java
@@ -343,36 +343,37 @@ public final class CharSequencesTest extends TestCase {
         assertFalse(isAcronymForWords("GC",     "Open Geospatial Consortium"));
         assertFalse(isAcronymForWords("ENE",    "NORTH_EAST"));
         /*
-         * Following are mapping of EPSG table names from MS-Access to ANSI 
SQL.
-         * All those items must be recognized as acroynms - this is requred by 
EPSGDataAccess.
+         * Following are mapping of table names between two variants of EPSG 
dataset.
+         * All those items shoud be recognized as acroynms, as this mapping is 
used
+         * by `EPSGDataAccess` for logging purposes.
          */
-        assertTrue(isAcronymForWords("alias",                     "[Alias]"));
-        assertTrue(isAcronymForWords("area",                      "[Area]"));
-        assertTrue(isAcronymForWords("coordinateaxis",            "[Coordinate 
Axis]"));
-        assertTrue(isAcronymForWords("coordinateaxisname",        "[Coordinate 
Axis Name]"));
-        assertTrue(isAcronymForWords("coordoperation",            
"[Coordinate_Operation]"));
-        assertTrue(isAcronymForWords("coordoperationmethod",      
"[Coordinate_Operation Method]"));
-        assertTrue(isAcronymForWords("coordoperationparam",       
"[Coordinate_Operation Parameter]"));
-        assertTrue(isAcronymForWords("coordoperationparamusage",  
"[Coordinate_Operation Parameter Usage]"));
-        assertTrue(isAcronymForWords("coordoperationparamvalue",  
"[Coordinate_Operation Parameter Value]"));
-        assertTrue(isAcronymForWords("coordoperationpath",        
"[Coordinate_Operation Path]"));
-        assertTrue(isAcronymForWords("coordinatereferencesystem", "[Coordinate 
Reference System]"));
-        assertTrue(isAcronymForWords("coordinatesystem",          "[Coordinate 
System]"));
-        assertTrue(isAcronymForWords("datum",                     "[Datum]"));
-        assertTrue(isAcronymForWords("ellipsoid",                 
"[Ellipsoid]"));
-        assertTrue(isAcronymForWords("namingsystem",              "[Naming 
System]"));
-        assertTrue(isAcronymForWords("primemeridian",             "[Prime 
Meridian]"));
-        assertTrue(isAcronymForWords("supersession",              
"[Supersession]"));
-        assertTrue(isAcronymForWords("unitofmeasure",             "[Unit of 
Measure]"));
-        assertTrue(isAcronymForWords("versionhistory",            "[Version 
History]"));
-        assertTrue(isAcronymForWords("change",                    "[Change]"));
-        assertTrue(isAcronymForWords("deprecation",               
"[Deprecation]"));
-        assertFalse(isAcronymForWords(null,                       
"[Deprecation]"));
+        assertTrue(isAcronymForWords("alias",                     "Alias"));
+        assertTrue(isAcronymForWords("area",                      "Area"));
+        assertTrue(isAcronymForWords("change",                    "Change"));
+        assertTrue(isAcronymForWords("coordinateaxis",            "Coordinate 
Axis"));
+        assertTrue(isAcronymForWords("coordinateaxisname",        "Coordinate 
Axis Name"));
+        assertTrue(isAcronymForWords("coordoperation",            
"Coordinate_Operation"));
+        assertTrue(isAcronymForWords("coordoperationmethod",      
"Coordinate_Operation Method"));
+        assertTrue(isAcronymForWords("coordoperationparam",       
"Coordinate_Operation Parameter"));
+        assertTrue(isAcronymForWords("coordoperationparamusage",  
"Coordinate_Operation Parameter Usage"));
+        assertTrue(isAcronymForWords("coordoperationparamvalue",  
"Coordinate_Operation Parameter Value"));
+        assertTrue(isAcronymForWords("coordoperationpath",        
"Coordinate_Operation Path"));
+        assertTrue(isAcronymForWords("coordinatereferencesystem", "Coordinate 
Reference System"));
+        assertTrue(isAcronymForWords("coordinatesystem",          "Coordinate 
System"));
+        assertTrue(isAcronymForWords("datum",                     "Datum"));
+        assertTrue(isAcronymForWords("deprecation",               
"Deprecation"));
+        assertTrue(isAcronymForWords("ellipsoid",                 
"Ellipsoid"));
+        assertTrue(isAcronymForWords("namingsystem",              "Naming 
System"));
+        assertTrue(isAcronymForWords("primemeridian",             "Prime 
Meridian"));
+        assertTrue(isAcronymForWords("supersession",              
"Supersession"));
+        assertTrue(isAcronymForWords("unitofmeasure",             "Unit of 
Measure"));
+        assertTrue(isAcronymForWords("versionhistory",            "Version 
History"));
+        assertFalse(isAcronymForWords(null,                       
"Deprecation"));
         /*
-         * It is important the following is not recognized as an acronym,
-         * otherwise it leads to a confusion in EPSGDataAccess.
+         * It is important that the following is not recognized as an acronym,
+         * otherwise it leads to a confusion in `EPSGDataAccess`.
          */
-        assertFalse(isAcronymForWords("coordoperation", "[Coordinate_Operation 
Method]"));
+        assertFalse(isAcronymForWords("coordoperation", "Coordinate_Operation 
Method"));
     }
 
     /**

Reply via email to