diff --git a/api/src/org/labkey/api/data/DbScope.java b/api/src/org/labkey/api/data/DbScope.java index 4a7b1e1ed75..d20efe56caa 100644 --- a/api/src/org/labkey/api/data/DbScope.java +++ b/api/src/org/labkey/api/data/DbScope.java @@ -368,6 +368,21 @@ public LabKeyDataSource(DataSource ds, String dsName) throws ServletException _dialect = SqlDialectManager.getFromDriverClassname(_dsName, _driverClassName); MemTracker.get().remove(_dialect); _driverClass = initializeDriver(); + + if (_dialect.isPostgreSQL()) + { + // Starting with PostgreSQL 17.x, we can't connect with a database name longer than 63 chars, so we have + // to truncate and replace the URL in the DataSource. Yuck. Issue #51676. + String url = _dsPropertyReader.getUrl(); + String name = _dialect.getDatabaseName(url); + if (name.length() > _dialect.getIdentifierMaxLength()) + { + String truncated = StringUtils.truncate(name, _dialect.getIdentifierMaxLength()); + String newUrl = url.replace(name, truncated); + _dsPropertyReader.setUrl(newUrl); + } + } + _url = _dsPropertyReader.getUrl(); // Validate that data source is using a supported connection pool diff --git a/api/src/org/labkey/api/data/LookupColumn.java b/api/src/org/labkey/api/data/LookupColumn.java index d2f110252f0..d4bf39aa5ca 100644 --- a/api/src/org/labkey/api/data/LookupColumn.java +++ b/api/src/org/labkey/api/data/LookupColumn.java @@ -24,10 +24,8 @@ import org.labkey.api.util.Pair; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; /** * A {@link org.labkey.api.data.ColumnInfo} that is part of a lookup target. This implementation knows @@ -133,7 +131,7 @@ public LookupColumn(ColumnInfo foreignKey, ColumnInfo lookupKey, ColumnInfo look _joinType = joinType; setSqlTypeName(lookupColumn.getSqlTypeName()); String alias = foreignKey.getAlias() + "$" + lookupColumn.getAlias(); - int maxLength = lookupColumn.getSqlDialect().getIdentifierMaxLength(); + int maxLength = lookupColumn.getSqlDialect().getIdentifierMaxLength() - 3; // Leave room for "$" and possible suffixes if (alias.length() > maxLength) alias = AliasManager.truncate(foreignKey.getAlias(),maxLength/2) + "$" + AliasManager.truncate(lookupColumn.getAlias(),maxLength/2); setAlias(alias); @@ -282,7 +280,7 @@ public static String getTableAlias(String baseAlias, String fkAlias, SqlDialect { String alias = baseAlias + (baseAlias.endsWith("$")?"":"$") + fkAlias + "$"; - alias = AliasManager.truncate(alias, dialect.getIdentifierMaxLength()); + alias = AliasManager.truncate(alias, dialect.getIdentifierMaxLength() - 3 /* leave room for possible suffixes */); return alias; } diff --git a/api/src/org/labkey/api/data/dialect/PostgreSql91Dialect.java b/api/src/org/labkey/api/data/dialect/PostgreSql91Dialect.java index f52eb5df07b..d5acb08de20 100644 --- a/api/src/org/labkey/api/data/dialect/PostgreSql91Dialect.java +++ b/api/src/org/labkey/api/data/dialect/PostgreSql91Dialect.java @@ -637,8 +637,7 @@ public String getCreateDatabaseSql(String dbName) { // This will handle both mixed case and special characters on PostgreSQL String legal = getSelectNameFromMetaDataName(dbName); - return "CREATE DATABASE " + legal + " WITH ENCODING 'UTF8';\n" + - "ALTER DATABASE " + legal + " SET default_with_oids TO OFF"; + return "CREATE DATABASE " + legal + " WITH ENCODING 'UTF8'"; } @Override diff --git a/api/src/org/labkey/api/data/dialect/SqlDialect.java b/api/src/org/labkey/api/data/dialect/SqlDialect.java index 77c3a06a594..bf5924f00f5 100644 --- a/api/src/org/labkey/api/data/dialect/SqlDialect.java +++ b/api/src/org/labkey/api/data/dialect/SqlDialect.java @@ -958,11 +958,13 @@ public void testKeywordCandidates(SqlExecutor executor) throws IOException, SQLE throw new IllegalStateException(getProductName() + " reserved words are not all in the keyword candidate list (sqlKeywords.txt). See log for details."); } + /** + * @return The absolute maximum length for this database. Callers are responsible for truncating generated names, + * handing suffixes, etc. + */ public int getIdentifierMaxLength() { - // 63 probably works, but save 2 chars for appending chars to - // create aliases for extra tables used in the lookup (e.g. junctionAlias = getTableAlias() + "_j") - return 61; + return 63; } protected SQLFragment getIdentifierTestSql(String candidate) @@ -1344,6 +1346,20 @@ public Long getMaxWaitMillis() return null; } } + + public void setUrl(String url) throws ServletException + { + String methodName = "setUrl"; + try + { + Method method = _ds.getClass().getMethod(methodName, String.class); + method.invoke(_ds, url); + } + catch (Exception e) + { + throw new ServletException("Unable to set DataSource property via " + methodName, e); + } + } } // All statement creation passes through these two methods. We return our standard statement wrappers in most diff --git a/api/src/org/labkey/api/query/AliasManager.java b/api/src/org/labkey/api/query/AliasManager.java index bb818b599c3..4c312b032bc 100644 --- a/api/src/org/labkey/api/query/AliasManager.java +++ b/api/src/org/labkey/api/query/AliasManager.java @@ -178,8 +178,7 @@ private static String makeLegalName(String str, @Nullable SqlDialect dialect, bo ret = "X_"; if (dialect != null) ret = dialect.makeLegalIdentifierName(ret); - // we use 28 here because Oracle has a limit or 30 characters, and that is likely the shortest restriction - int maxLength = useLegacyMaxLength ? 40 : (dialect == null ? 28 : dialect.getIdentifierMaxLength()); + int maxLength = getMaxLength(dialect, useLegacyMaxLength); if (reserveCount > 0) maxLength -= reserveCount; if (maxLength < 5) @@ -202,12 +201,18 @@ public static String makeLegalName(FieldKey key, @Nullable SqlDialect dialect, b sb.append(legalNameFromName(part)); connector = "_"; } - // we use 28 here because Oracle has a limit or 30 characters, and that is likely the shortest restriction - var ret = truncate(sb.toString(), useLegacyMaxLength ? 40 : (dialect == null ? 28 : dialect.getIdentifierMaxLength())); + var ret = truncate(sb.toString(), getMaxLength(dialect, useLegacyMaxLength)); assert isLegalName(ret); return ret; } + private static int getMaxLength(@Nullable SqlDialect dialect, boolean useLegacyMaxLength) + { + // we use 28 here because Oracle has a limit of 30 characters, and that is likely the shortest restriction + + // But note: Oracle 12c raised the limit to 128 characters, so perhaps increase the fall-back length now? + return useLegacyMaxLength ? 40 : (dialect == null ? 28 : dialect.getIdentifierMaxLength() - 3 /* leave room for possible suffixes */); + } public static String truncate(String str, int to) { @@ -375,7 +380,7 @@ public boolean isReserved(String word) assertEquals("select_", m.decideAlias("select")); - assertEquals(m._dialect.getIdentifierMaxLength(), m.decideAlias("This is a very long name for a column, but it happens! go figure.").length()); + assertEquals(m._dialect.getIdentifierMaxLength() - 3, m.decideAlias("This is a very long name for a column, but it happens! go figure. " + StringUtils.repeat('x', 100)).length()); } } }