diff --git a/src/NHibernate.Test/MappingTest/ColumnFixture.cs b/src/NHibernate.Test/MappingTest/ColumnFixture.cs index 8b1168fe12d..94f6a8c4c12 100644 --- a/src/NHibernate.Test/MappingTest/ColumnFixture.cs +++ b/src/NHibernate.Test/MappingTest/ColumnFixture.cs @@ -39,5 +39,53 @@ public void StringSqlType() column.Length = 100; Assert.AreEqual("NVARCHAR(100)", column.GetSqlType(_dialect, null)); } + + + [TestCase("xxxxyyyyz")] + [TestCase("xxxxyyyyzz")] + [TestCase("xxxxyyyyzzz")] + [TestCase("xxxxyyy4z", Description = "Non-letter digit character would be cut, make sure we don't skip length check.")] + [TestCase("xxxxyyyz4z", Description = "Non-letter digit character would be cut, make sure we don't skip length check.")] + [TestCase("xxxxyyyzz4z", Description = "Non-letter digit character would be cut, make sure we don't skip length check.")] + [TestCase("xxxxyyyy4", Description = "Non-letter digit character would be cut, make sure we don't skip length check.")] + [TestCase("xxxxyyyyz4", Description = "Non-letter digit character would be cut, make sure we don't skip length check.")] + [TestCase("xxxxyyyyzz4", Description = "Non-letter digit character would be cut, make sure we don't skip length check.")] + public void GetAliasRespectsMaxAliasLength(string columnName) + { + var dialect = new GenericDialect(); + + // Verify test case assumption. + Assert.That(dialect.MaxAliasLength, Is.EqualTo(10)); + + var column = new Column(columnName); + string generatedAlias = column.GetAlias(dialect); + + Assert.That(generatedAlias, Has.Length.LessThanOrEqualTo(dialect.MaxAliasLength)); + } + + + [TestCase("xxxxyyyyz")] + [TestCase("xxxxyyyyzz")] + [TestCase("xxxxyyyyzzz")] + [TestCase("xxxxyyy4z")] + [TestCase("xxxxyyyz4z")] + [TestCase("xxxxyyyzz4z")] + [TestCase("xxxxyyyy4")] + [TestCase("xxxxyyyyz4")] + [TestCase("xxxxyyyyzz4")] + public void GetAliasWithTableSuffixRespectsMaxAliasLength(string columnName) + { + var dialect = new GenericDialect(); + + // Verify test case assumption. + Assert.That(dialect.MaxAliasLength, Is.EqualTo(10)); + + var table = new Table(); + var column = new Column(columnName); + + string generatedAlias = column.GetAlias(dialect, table); + + Assert.That(generatedAlias, Has.Length.LessThanOrEqualTo(dialect.MaxAliasLength)); + } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Mapping/Column.cs b/src/NHibernate/Mapping/Column.cs index 4534acfd778..4ccea5fca63 100644 --- a/src/NHibernate/Mapping/Column.cs +++ b/src/NHibernate/Mapping/Column.cs @@ -115,16 +115,21 @@ public string GetQuotedName(Dialect.Dialect d) return IsQuoted ? d.QuoteForColumnName(_name) : _name; } - /** - * For any column name, generate an alias that is unique - * to that column name, and also 10 characters or less - * in length. - */ + /// + /// For any column name, generate an alias that is unique to that + /// column name, and also take Dialect.MaxAliasLength into account. + /// public string GetAlias(Dialect.Dialect dialect) + { + return GetAlias(dialect.MaxAliasLength); + } + + private string GetAlias(int maxAliasLength) { string alias = _name; - string suffix = UniqueInteger.ToString() + '_'; + string suffix = UniqueInteger.ToString() + StringHelper.Underscore; + int lastLetter = StringHelper.LastIndexOfLetter(_name); if (lastLetter == -1) { @@ -134,27 +139,38 @@ public string GetAlias(Dialect.Dialect dialect) { alias = _name.Substring(0, lastLetter + 1); } - if (alias.Length > dialect.MaxAliasLength) - { - alias = alias.Substring(0, dialect.MaxAliasLength - suffix.Length); - } - bool useRawName = _name.Equals(alias) && - !_quoted && - !StringHelper.EqualsCaseInsensitive(_name, "rowid"); - if (useRawName) - { - return alias; - } - else + // Updated logic ported from Hibernate's fix for HHH-8073. + // https://github.com/hibernate/hibernate-orm/commit/79073a98f0e4ed225fe4608b67594196f86d48d7 + // To my mind it is weird - since the suffix is now always used, it + // seems "useRawName" is a misleading choice of variable name. For the same + // reason, the checks for "_quoted" and "rowid" looks redundant. If you remove + // those checks, then the double checks for total length can be reduced to one. + // But I will leave it like this for now to make it look similar. /Oskar 2016-08-20 + bool useRawName = _name.Length + suffix.Length <= maxAliasLength && + !_quoted && + !StringHelper.EqualsCaseInsensitive(_name, "rowid"); + if (!useRawName) { - return alias + suffix; + if (suffix.Length >= maxAliasLength) + { + throw new MappingException( + string.Format( + "Unique suffix {0} length must be less than maximum {1} characters.", + suffix, + maxAliasLength)); + } + if (alias.Length + suffix.Length > maxAliasLength) + alias = alias.Substring(0, maxAliasLength - suffix.Length); } + return alias + suffix; } public string GetAlias(Dialect.Dialect dialect, Table table) { - return GetAlias(dialect) + table.UniqueInteger + StringHelper.Underscore; + string suffix = table.UniqueInteger.ToString() + StringHelper.Underscore; + int maxAliasLength = dialect.MaxAliasLength - suffix.Length; + return GetAlias(maxAliasLength) + suffix; }