Skip to content

Commit 1734eb2

Browse files
ngbrownhazzik
authored andcommitted
NH-3158 - Use Dialect.Keywords for auto-quoting
- Dialect encapsulates Keywords - Use case-insensitive HashSet for keywords - AbstractDataBaseSchema and SybaseAnywhereColumnMetaData return case insensitive hash set (in fact, they can return an array/IEnumerable<string> instead of ISet<string>) - SchemaMetadataUpdater just sets IsQuoted for table and column names, so it does not do unnecessary string operations - Initialize SchemaUpdate once
1 parent 38ead3f commit 1734eb2

File tree

11 files changed

+115
-68
lines changed

11 files changed

+115
-68
lines changed

src/NHibernate.Test/Tools/hbm2ddl/SchemaMetadataUpdaterTest/HeavyEntity.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ public class Order
77
public string And { get; set; }
88
public string Column { get; set; }
99
public string Name { get; set; }
10+
public string Abracadabra { get; set; }
1011
}
1112
}

src/NHibernate.Test/Tools/hbm2ddl/SchemaMetadataUpdaterTest/HeavyEntity.hbm.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<property name="And"/>
1414
<property name="Column"/>
1515
<property name="Name"/>
16+
<property name="Abracadabra"/>
1617
</class>
1718

1819
</hibernate-mapping>

src/NHibernate.Test/Tools/hbm2ddl/SchemaMetadataUpdaterTest/SchemaMetadataUpdaterFixture.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Linq;
34
using NHibernate.Cfg;
45
using NHibernate.Engine;
56
using NHibernate.Mapping;
67
using NHibernate.Tool.hbm2ddl;
78
using NUnit.Framework;
9+
using Environment = NHibernate.Cfg.Environment;
810

911
namespace NHibernate.Test.Tools.hbm2ddl.SchemaMetadataUpdaterTest
1012
{
@@ -23,8 +25,8 @@ public void CanRetrieveReservedWords()
2325
var metaData = dialect.GetDataBaseSchema(connectionHelper.Connection);
2426
var reserved = metaData.GetReservedWords();
2527
Assert.That(reserved, Is.Not.Empty);
26-
Assert.That(reserved, Has.Member("SELECT"));
27-
Assert.That(reserved, Has.Member("FROM"));
28+
Assert.That(reserved, Has.Member("SELECT").IgnoreCase);
29+
Assert.That(reserved, Has.Member("FROM").IgnoreCase);
2830
}
2931
finally
3032
{
@@ -35,7 +37,7 @@ public void CanRetrieveReservedWords()
3537
[Test]
3638
public void UpdateReservedWordsInDialect()
3739
{
38-
var reservedDb = new HashSet<string>();
40+
var reservedDb = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
3941
var configuration = TestConfigurationHelper.GetDefaultConfiguration();
4042
var dialect = Dialect.Dialect.GetDialect(configuration.Properties);
4143
var connectionHelper = new ManagedProviderConnectionHelper(configuration.Properties);
@@ -55,7 +57,7 @@ public void UpdateReservedWordsInDialect()
5557

5658
var sf = (ISessionFactoryImplementor) configuration.BuildSessionFactory();
5759
SchemaMetadataUpdater.Update(sf);
58-
var match = reservedDb.Intersect(sf.Dialect.Keywords);
60+
var match = reservedDb.Intersect(sf.Dialect.Keywords, StringComparer.OrdinalIgnoreCase);
5961
Assert.That(match, Is.EquivalentTo(reservedDb));
6062
}
6163

@@ -66,14 +68,19 @@ public void ExplicitAutoQuote()
6668
configuration.AddResource("NHibernate.Test.Tools.hbm2ddl.SchemaMetadataUpdaterTest.HeavyEntity.hbm.xml",
6769
GetType().Assembly);
6870

69-
SchemaMetadataUpdater.QuoteTableAndColumns(configuration);
71+
var dialect = Dialect.Dialect.GetDialect(configuration.GetDerivedProperties());
72+
dialect.Keywords.Add("Abracadabra");
73+
74+
SchemaMetadataUpdater.Update(configuration, dialect);
75+
SchemaMetadataUpdater.QuoteTableAndColumns(configuration, dialect);
7076

7177
var cm = configuration.GetClassMapping(typeof(Order));
7278
Assert.That(cm.Table.IsQuoted);
7379
var culs = new List<Column>(cm.Table.ColumnIterator);
7480
Assert.That(GetColumnByName(culs, "From").IsQuoted);
7581
Assert.That(GetColumnByName(culs, "And").IsQuoted);
7682
Assert.That(GetColumnByName(culs, "Select").IsQuoted);
83+
Assert.That(GetColumnByName(culs, "Abracadabra").IsQuoted);
7784
Assert.That(!GetColumnByName(culs, "Name").IsQuoted);
7885
}
7986

@@ -97,7 +104,7 @@ public void AutoQuoteTableAndColumnsAtStratup()
97104
[Test]
98105
public void AutoQuoteTableAndColumnsAtStratupIncludeKeyWordsImport()
99106
{
100-
var reservedDb = new HashSet<string>();
107+
var reservedDb = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
101108
var configuration = TestConfigurationHelper.GetDefaultConfiguration();
102109
var dialect = Dialect.Dialect.GetDialect(configuration.Properties);
103110
var connectionHelper = new ManagedProviderConnectionHelper(configuration.Properties);
@@ -119,8 +126,8 @@ public void AutoQuoteTableAndColumnsAtStratupIncludeKeyWordsImport()
119126
configuration.AddResource("NHibernate.Test.Tools.hbm2ddl.SchemaMetadataUpdaterTest.HeavyEntity.hbm.xml",
120127
GetType().Assembly);
121128
var sf = (ISessionFactoryImplementor)configuration.BuildSessionFactory();
122-
var match = reservedDb.Intersect(sf.Dialect.Keywords);
123-
Assert.That(match, Is.EquivalentTo(reservedDb));
129+
var match = reservedDb.Intersect(sf.Dialect.Keywords, StringComparer.OrdinalIgnoreCase);
130+
Assert.That(match, Is.EquivalentTo(reservedDb).IgnoreCase);
124131
}
125132

126133
private static Column GetColumnByName(IEnumerable<Column> columns, string colName)
@@ -167,14 +174,19 @@ public void WhenConfiguredOnlyExplicitAutoQuote()
167174
configuration.AddResource("NHibernate.Test.Tools.hbm2ddl.SchemaMetadataUpdaterTest.HeavyEntity.hbm.xml",
168175
GetType().Assembly);
169176

170-
SchemaMetadataUpdater.QuoteTableAndColumns(configuration);
177+
var dialect = Dialect.Dialect.GetDialect(configuration.GetDerivedProperties());
178+
dialect.Keywords.Add("Abracadabra");
179+
180+
SchemaMetadataUpdater.Update(configuration, dialect);
181+
SchemaMetadataUpdater.QuoteTableAndColumns(configuration, dialect);
171182

172183
var cm = configuration.GetClassMapping(typeof(Order));
173184
Assert.That(cm.Table.IsQuoted);
174185
var culs = new List<Column>(cm.Table.ColumnIterator);
175186
Assert.That(GetColumnByName(culs, "From").IsQuoted);
176187
Assert.That(GetColumnByName(culs, "And").IsQuoted);
177188
Assert.That(GetColumnByName(culs, "Select").IsQuoted);
189+
Assert.That(GetColumnByName(culs, "Abracadabra").IsQuoted);
178190
Assert.That(!GetColumnByName(culs, "Name").IsQuoted);
179191
}
180192
}

src/NHibernate/Dialect/Dialect.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public abstract class Dialect
4444
private readonly TypeNames _hibernateTypeNames = new TypeNames();
4545
private readonly IDictionary<string, string> _properties = new Dictionary<string, string>();
4646
private readonly IDictionary<string, ISQLFunction> _sqlFunctions;
47-
private readonly HashSet<string> _sqlKeywords = new HashSet<string>();
4847

4948
private static readonly IDictionary<string, ISQLFunction> StandardAggregateFunctions = CollectionHelper.CreateCaseInsensitiveHashtable<ISQLFunction>();
5049

@@ -81,7 +80,9 @@ protected Dialect()
8180
Log.Info("Using dialect: " + this);
8281

8382
_sqlFunctions = CollectionHelper.CreateCaseInsensitiveHashtable(StandardAggregateFunctions);
84-
83+
84+
Keywords = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
85+
8586
// standard sql92 functions (can be overridden by subclasses)
8687
RegisterFunction("substring", new AnsiSubstringFunction());
8788
RegisterFunction("locate", new StandardSQLFunction("locate", NHibernateUtil.Int32));
@@ -2086,10 +2087,7 @@ public virtual IDictionary<string, ISQLFunction> Functions
20862087
get { return _sqlFunctions; }
20872088
}
20882089

2089-
public HashSet<string> Keywords
2090-
{
2091-
get { return _sqlKeywords; }
2092-
}
2090+
public HashSet<string> Keywords { get; }
20932091

20942092
/// <summary>
20952093
/// Get the command used to select a GUID from the underlying database.
@@ -2246,6 +2244,21 @@ protected void RegisterKeyword(string word)
22462244
Keywords.Add(word);
22472245
}
22482246

2247+
protected internal void RegisterKeywords(params string[] keywords)
2248+
{
2249+
Keywords.UnionWith(keywords);
2250+
}
2251+
2252+
protected internal void RegisterKeywords(IEnumerable<string> keywords)
2253+
{
2254+
Keywords.UnionWith(keywords);
2255+
}
2256+
2257+
public bool IsKeyword(string str)
2258+
{
2259+
return Keywords.Contains(str);
2260+
}
2261+
22492262
protected void RegisterFunction(string name, ISQLFunction function)
22502263
{
22512264
_sqlFunctions[name] = function;
@@ -2281,4 +2294,4 @@ public virtual ISQLExceptionConverter BuildSQLExceptionConverter()
22812294
return new SQLStateConverter(ViolatedConstraintNameExtracter);
22822295
}
22832296
}
2284-
}
2297+
}

src/NHibernate/Dialect/Schema/AbstractDataBaseSchema.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Data;
34
using System.Data.Common;
@@ -93,7 +94,7 @@ public virtual DataTable GetForeignKeys(string catalog, string schema, string ta
9394

9495
public virtual ISet<string> GetReservedWords()
9596
{
96-
var result = new HashSet<string>();
97+
var result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
9798
DataTable dtReservedWords = connection.GetSchema(DbMetaDataCollectionNames.ReservedWords);
9899
foreach (DataRow row in dtReservedWords.Rows)
99100
{
@@ -109,4 +110,4 @@ protected virtual string ForeignKeysSchemaName
109110

110111
#endregion
111112
}
112-
}
113+
}

src/NHibernate/Dialect/Schema/SybaseAnywhereMetaData.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public override ITableMetadata GetTableMetadata(DataRow rs, bool extras)
1818

1919
public override ISet<string> GetReservedWords()
2020
{
21-
var result = new HashSet<string>();
21+
var result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
2222
DataTable dtReservedWords = Connection.GetSchema(DbMetaDataCollectionNames.ReservedWords);
2323
foreach (DataRow row in dtReservedWords.Rows)
2424
{
@@ -143,4 +143,4 @@ public SybaseAnywhereForeignKeyMetaData(DataRow rs) : base(rs)
143143
Name = (string) rs["COLUMN_NAME"];
144144
}
145145
}
146-
}
146+
}

src/NHibernate/Impl/SessionFactoryImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
201201
}
202202
if (settings.IsAutoQuoteEnabled)
203203
{
204-
SchemaMetadataUpdater.QuoteTableAndColumns(cfg);
204+
SchemaMetadataUpdater.QuoteTableAndColumns(cfg, Dialect);
205205
}
206206
}
207207
catch (NotSupportedException)

src/NHibernate/SqlCommand/Template.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ private static bool IsFunctionOrKeyword(string lcToken, string nextToken, Dialec
308308
return "(".Equals(nextToken) ||
309309
Keywords.Contains(lcToken) ||
310310
functionRegistry.HasFunction(lcToken) ||
311-
dialect.Keywords.Contains(lcToken) ||
311+
dialect.IsKeyword(lcToken) ||
312312
dialect.IsKnownToken(lcToken, nextToken) ||
313313
FunctionKeywords.Contains(lcToken);
314314
}
@@ -321,4 +321,4 @@ private static bool IsIdentifier(string token, Dialect.Dialect dialect)
321321
);
322322
}
323323
}
324-
}
324+
}

src/NHibernate/Tool/hbm2ddl/SchemaExport.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,16 @@ private void Initialize()
5656
{
5757
return;
5858
}
59+
dialect = Dialect.Dialect.GetDialect(configProperties);
60+
5961
string autoKeyWordsImport = PropertiesHelper.GetString(Environment.Hbm2ddlKeyWords, configProperties, "not-defined");
6062
autoKeyWordsImport = autoKeyWordsImport.ToLowerInvariant();
6163
if (autoKeyWordsImport == Hbm2DDLKeyWords.AutoQuote)
6264
{
63-
SchemaMetadataUpdater.QuoteTableAndColumns(cfg);
65+
SchemaMetadataUpdater.Update(cfg, dialect);
66+
SchemaMetadataUpdater.QuoteTableAndColumns(cfg, dialect);
6467
}
6568

66-
dialect = Dialect.Dialect.GetDialect(configProperties);
6769
dropSQL = cfg.GenerateDropSchemaScript(dialect);
6870
createSQL = cfg.GenerateSchemaCreationScript(dialect);
6971
formatter = (PropertiesHelper.GetBoolean(Environment.FormatSql, configProperties, true) ? FormatStyle.Ddl : FormatStyle.None).Formatter;
Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using NHibernate.Cfg;
23
using NHibernate.Engine;
34
using NHibernate.Mapping;
@@ -8,71 +9,73 @@ namespace NHibernate.Tool.hbm2ddl
89
// Candidate to be exstensions of ISessionFactory and Configuration
910
public static class SchemaMetadataUpdater
1011
{
11-
public static void Update(ISessionFactory sessionFactory)
12+
public static void Update(ISessionFactoryImplementor sessionFactory)
1213
{
13-
var factory = (ISessionFactoryImplementor) sessionFactory;
14-
var dialect = factory.Dialect;
15-
var connectionHelper = new SuppliedConnectionProviderConnectionHelper(factory.ConnectionProvider);
16-
factory.Dialect.Keywords.UnionWith(GetReservedWords(dialect, connectionHelper));
14+
UpdateDialectKeywords(
15+
sessionFactory.Dialect,
16+
new SuppliedConnectionProviderConnectionHelper(sessionFactory.ConnectionProvider));
1717
}
1818

19-
public static void QuoteTableAndColumns(Configuration configuration)
19+
public static void Update(Configuration configuration, Dialect.Dialect dialect)
2020
{
21-
ISet<string> reservedDb = GetReservedWords(configuration.GetDerivedProperties());
22-
foreach (var cm in configuration.ClassMappings)
23-
{
24-
QuoteTable(cm.Table, reservedDb);
25-
}
26-
foreach (var cm in configuration.CollectionMappings)
27-
{
28-
QuoteTable(cm.Table, reservedDb);
29-
}
21+
UpdateDialectKeywords(
22+
dialect,
23+
new ManagedProviderConnectionHelper(configuration.GetDerivedProperties()));
3024
}
3125

32-
private static ISet<string> GetReservedWords(IDictionary<string, string> cfgProperties)
26+
static void UpdateDialectKeywords(Dialect.Dialect dialect, IConnectionHelper connectionHelper)
3327
{
34-
var dialect = Dialect.Dialect.GetDialect(cfgProperties);
35-
var connectionHelper = new ManagedProviderConnectionHelper(cfgProperties);
36-
return GetReservedWords(dialect, connectionHelper);
28+
dialect.RegisterKeywords(GetReservedWords(dialect, connectionHelper));
3729
}
3830

39-
private static ISet<string> GetReservedWords(Dialect.Dialect dialect, IConnectionHelper connectionHelper)
31+
static IEnumerable<string> GetReservedWords(Dialect.Dialect dialect, IConnectionHelper connectionHelper)
4032
{
41-
ISet<string> reservedDb = new HashSet<string>();
4233
connectionHelper.Prepare();
4334
try
4435
{
4536
var metaData = dialect.GetDataBaseSchema(connectionHelper.Connection);
46-
foreach (var rw in metaData.GetReservedWords())
47-
{
48-
reservedDb.Add(rw.ToLowerInvariant());
49-
}
37+
return metaData.GetReservedWords();
5038
}
5139
finally
5240
{
5341
connectionHelper.Release();
5442
}
55-
return reservedDb;
5643
}
5744

58-
private static void QuoteTable(Table table, ICollection<string> reservedDb)
45+
[Obsolete("Use the overload that passes dialect so keywords will be updated and persisted before auto-quoting")]
46+
public static void QuoteTableAndColumns(Configuration configuration)
47+
{
48+
// Instantiates a new instance of the dialect so doesn't benefit from the Update call.
49+
var dialect = Dialect.Dialect.GetDialect(configuration.GetDerivedProperties());
50+
Update(configuration, dialect);
51+
QuoteTableAndColumns(configuration, dialect);
52+
}
53+
54+
public static void QuoteTableAndColumns(Configuration configuration, Dialect.Dialect dialect)
5955
{
60-
if (!table.IsQuoted && reservedDb.Contains(table.Name.ToLowerInvariant()))
56+
foreach (var cm in configuration.ClassMappings)
6157
{
62-
table.Name = GetNhQuoted(table.Name);
58+
QuoteTable(cm.Table, dialect);
6359
}
64-
foreach (var column in table.ColumnIterator)
60+
foreach (var cm in configuration.CollectionMappings)
6561
{
66-
if (!column.IsQuoted && reservedDb.Contains(column.Name.ToLowerInvariant()))
67-
{
68-
column.Name = GetNhQuoted(column.Name);
69-
}
62+
QuoteTable(cm.Table, dialect);
7063
}
7164
}
7265

73-
private static string GetNhQuoted(string name)
66+
private static void QuoteTable(Table table, Dialect.Dialect dialect)
7467
{
75-
return "`" + name + "`";
68+
if (!table.IsQuoted && dialect.IsKeyword(table.Name))
69+
{
70+
table.IsQuoted = true;
71+
}
72+
foreach (var column in table.ColumnIterator)
73+
{
74+
if (!column.IsQuoted && dialect.IsKeyword(column.Name))
75+
{
76+
column.IsQuoted = true;
77+
}
78+
}
7679
}
7780
}
78-
}
81+
}

0 commit comments

Comments
 (0)