Skip to content

Commit 956bffe

Browse files
bahusoidfredericDelaporte
authored andcommitted
Various string manipulation optimizations (#1543)
* Avoid code duplication for Root determination - added IsNotRoot * string.IndexOf ordinal comparison where applicable * Avoid full string conversion * SqlString avoid ToString conversion * Generalized HqlVariable determination - introduced ParserHelper.HasHqlVariable and ParserHelper.IsHqlVariable
1 parent fe84b90 commit 956bffe

File tree

14 files changed

+102
-49
lines changed

14 files changed

+102
-49
lines changed

src/NHibernate/AdoNet/Util/BasicFormatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ private static bool IsFunctionName(string tok)
430430

431431
private static bool IsWhitespace(string token)
432432
{
433-
return StringHelper.WhiteSpace.IndexOf(token) >= 0;
433+
return StringHelper.WhiteSpace.IndexOf(token, StringComparison.Ordinal) >= 0;
434434
}
435435

436436
private void Newline()
@@ -451,4 +451,4 @@ public void Dispose()
451451

452452
#endregion
453453
}
454-
}
454+
}

src/NHibernate/AdoNet/Util/DdlFormatter.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Text;
34
using NHibernate.Util;
@@ -18,15 +19,15 @@ public class DdlFormatter: IFormatter
1819
/// </summary>
1920
public virtual string Format(string sql)
2021
{
21-
if (sql.ToLowerInvariant().StartsWith("create table"))
22+
if (sql.StartsWith("create table", StringComparison.OrdinalIgnoreCase))
2223
{
2324
return FormatCreateTable(sql);
2425
}
25-
else if (sql.ToLowerInvariant().StartsWith("alter table"))
26+
else if (sql.StartsWith("alter table", StringComparison.OrdinalIgnoreCase))
2627
{
2728
return FormatAlterTable(sql);
2829
}
29-
else if (sql.ToLowerInvariant().StartsWith("comment on"))
30+
else if (sql.StartsWith("comment on", StringComparison.OrdinalIgnoreCase))
3031
{
3132
return FormatCommentOn(sql);
3233
}
@@ -138,4 +139,4 @@ private static bool IsQuote(string token)
138139
return "\"".Equals(token) || "`".Equals(token) || "]".Equals(token) || "[".Equals(token) || "'".Equals(token);
139140
}
140141
}
141-
}
142+
}

src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private void BindCollection(ICollectionPropertiesMapping collectionMapping, Mapp
221221

222222
//ORPHAN DELETE (used for programmer error detection)
223223
var cascadeAtt = collectionMapping.Cascade;
224-
if (!string.IsNullOrEmpty(cascadeAtt) && cascadeAtt.IndexOf("delete-orphan") >= 0)
224+
if (!string.IsNullOrEmpty(cascadeAtt) && cascadeAtt.IndexOf("delete-orphan", StringComparison.Ordinal) >= 0)
225225
model.HasOrphanDelete = true;
226226

227227
// GENERIC

src/NHibernate/Engine/Query/CallableParser.cs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ public static Detail Parse(string sqlString)
2121
{
2222
Detail callableDetail = new Detail();
2323

24-
callableDetail.IsCallable = sqlString.IndexOf("{") == 0 &&
25-
sqlString.IndexOf("}") == (sqlString.Length - 1) &&
26-
sqlString.IndexOf("call") > 0;
24+
int indexOfCall = -1;
25+
callableDetail.IsCallable = sqlString.Length > 5 && // to be able to check sqlString[0] we at least need to make sure that string has at least 1 character. The simplest case all other conditions are true is "{call}" which is 6 characters, so check it.
26+
sqlString[0] == '{' &&
27+
sqlString[sqlString.Length - 1] == '}' &&
28+
(indexOfCall = sqlString.IndexOf("call", StringComparison.Ordinal)) > 0;
2729

2830
if (!callableDetail.IsCallable)
2931
return callableDetail;
@@ -35,13 +37,20 @@ public static Detail Parse(string sqlString)
3537

3638
callableDetail.FunctionName = functionMatch.Groups[1].Value;
3739

38-
callableDetail.HasReturn = sqlString.IndexOf("call") > 0 &&
39-
sqlString.IndexOf("?") > 0 &&
40-
sqlString.IndexOf("=") > 0 &&
41-
sqlString.IndexOf("?") < sqlString.IndexOf("call") &&
42-
sqlString.IndexOf("=") < sqlString.IndexOf("call");
40+
callableDetail.HasReturn = HasReturnParameter(sqlString, indexOfCall);
4341

4442
return callableDetail;
4543
}
44+
45+
internal static bool HasReturnParameter(string sqlString, int indexOfCall)
46+
{
47+
int indexOfQuestionMark;
48+
int indexOfEqual;
49+
return indexOfCall > 0 &&
50+
(indexOfQuestionMark = sqlString.IndexOf('?')) > 0 &&
51+
(indexOfEqual = sqlString.IndexOf('=')) > 0 &&
52+
indexOfQuestionMark < indexOfCall &&
53+
indexOfEqual < indexOfCall;
54+
}
4655
}
47-
}
56+
}

src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public int PerformExecuteUpdate(QueryParameters queryParameters, ISessionImpleme
120120
private SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollection<IParameterSpecification> parameterSpecs, ISessionImplementor session)
121121
{
122122
var enabledFilters = session.EnabledFilters;
123-
if (enabledFilters.Count == 0 || sqlString.ToString().IndexOf(ParserHelper.HqlVariablePrefix) < 0)
123+
if (enabledFilters.Count == 0 || !ParserHelper.HasHqlVariable(sqlString))
124124
{
125125
return sqlString;
126126
}
@@ -143,7 +143,7 @@ private SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollection
143143

144144
foreach (string token in tokens)
145145
{
146-
if (token.StartsWith(ParserHelper.HqlVariablePrefix))
146+
if (ParserHelper.IsHqlVariable(token))
147147
{
148148
string filterParameterName = token.Substring(1);
149149
string[] parts = StringHelper.ParseFilterParameterName(filterParameterName);

src/NHibernate/Engine/Query/ParameterParser.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,8 @@ private ParameterParser()
4242
public static void Parse(string sqlString, IRecognizer recognizer)
4343
{
4444
// TODO: WTF? "CALL"... it may work for ORACLE but what about others RDBMS ? (by FM)
45-
bool hasMainOutputParameter = sqlString.IndexOf("call") > 0 &&
46-
sqlString.IndexOf("?") > 0 &&
47-
sqlString.IndexOf("=") > 0 &&
48-
sqlString.IndexOf("?") < sqlString.IndexOf("call") &&
49-
sqlString.IndexOf("=") < sqlString.IndexOf("call");
45+
var indexOfCall = sqlString.IndexOf("call", StringComparison.Ordinal);
46+
bool hasMainOutputParameter = CallableParser.HasReturnParameter(sqlString, indexOfCall);
5047
bool foundMainOutputParam = false;
5148

5249
int stringLength = sqlString.Length;
@@ -59,7 +56,7 @@ public static void Parse(string sqlString, IRecognizer recognizer)
5956
// check comments
6057
if (indx + 1 < stringLength && sqlString.Substring(indx,2) == "/*")
6158
{
62-
var closeCommentIdx = sqlString.IndexOf("*/", indx+2);
59+
var closeCommentIdx = sqlString.IndexOf("*/", indx + 2, StringComparison.Ordinal);
6360
recognizer.Other(sqlString.Substring(indx, (closeCommentIdx- indx)+2));
6461
indx = closeCommentIdx + 1;
6562
continue;
@@ -112,7 +109,7 @@ public static void Parse(string sqlString, IRecognizer recognizer)
112109
if (c == ':')
113110
{
114111
// named parameter
115-
int right = StringHelper.FirstIndexOfChar(sqlString, ParserHelper.HqlSeparators, indx + 1);
112+
int right = StringHelper.FirstIndexOfChar(sqlString, ParserHelper.HqlSeparatorsAsCharArray, indx + 1);
116113
int chopLocation = right < 0 ? sqlString.Length : right;
117114
string param = sqlString.Substring(indx + 1, chopLocation - (indx + 1));
118115
recognizer.NamedParameter(param, indx);
@@ -124,7 +121,7 @@ public static void Parse(string sqlString, IRecognizer recognizer)
124121
if (indx < stringLength - 1 && char.IsDigit(sqlString[indx + 1]))
125122
{
126123
// a peek ahead showed this as an ejb3-positional parameter
127-
int right = StringHelper.FirstIndexOfChar(sqlString, ParserHelper.HqlSeparators, indx + 1);
124+
int right = StringHelper.FirstIndexOfChar(sqlString, ParserHelper.HqlSeparatorsAsCharArray, indx + 1);
128125
int chopLocation = right < 0 ? sqlString.Length : right;
129126
string param = sqlString.Substring(indx + 1, chopLocation - (indx + 1));
130127
// make sure this "name" is an integral
@@ -160,4 +157,4 @@ public static void Parse(string sqlString, IRecognizer recognizer)
160157
}
161158
}
162159
}
163-
}
160+
}

src/NHibernate/Hql/Ast/ANTLR/Util/JoinProcessor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,12 @@ public static void ProcessDynamicFilterParameters(
168168

169169
private static bool HasDynamicFilterParam(SqlString sqlFragment)
170170
{
171-
return sqlFragment.IndexOfCaseInsensitive(ParserHelper.HqlVariablePrefix) < 0;
171+
return !ParserHelper.HasHqlVariable(sqlFragment);
172172
}
173173

174174
private static bool HasCollectionFilterParam(SqlString sqlFragment)
175175
{
176-
return sqlFragment.IndexOfCaseInsensitive("?") < 0;
176+
return sqlFragment.IndexOfOrdinal("?") < 0;
177177
}
178178

179179
private class JoinSequenceSelector : JoinSequence.ISelector

src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void AddWhereFragment(
7474
if (hqlSqlWalker.IsFilter())
7575
{
7676
//if (whereFragment.IndexOfCaseInsensitive("?") >= 0)
77-
if (whereFragment.ToString().IndexOf("?") >= 0)
77+
if (whereFragment.IndexOfOrdinal("?") >= 0)
7878
{
7979
IType collectionFilterKeyType = hqlSqlWalker.SessionFactoryHelper
8080
.RequireQueryableCollection(hqlSqlWalker.CollectionFilterRole)

src/NHibernate/Hql/ParserHelper.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
using System;
2+
using NHibernate.SqlCommand;
3+
14
namespace NHibernate.Hql
25
{
36
public static class ParserHelper
47
{
58
public const string HqlVariablePrefix = ":";
69

710
public const string HqlSeparators = " \n\r\f\t,()=<>&|+-=/*'^![]#~\\;";
11+
internal static readonly char[] HqlSeparatorsAsCharArray = HqlSeparators.ToCharArray();
812
//NOTICE: no " or . since they are part of (compound) identifiers
913

1014
public const string Whitespace = " \n\r\f\t";
@@ -13,7 +17,22 @@ public static class ParserHelper
1317

1418
public static bool IsWhitespace(string str)
1519
{
16-
return Whitespace.IndexOf(str) > - 1;
20+
return Whitespace.IndexOf(str, StringComparison.Ordinal) > - 1;
21+
}
22+
23+
internal static bool HasHqlVariable(string value)
24+
{
25+
return value.IndexOf(HqlVariablePrefix, StringComparison.Ordinal) >= 0;
26+
}
27+
28+
internal static bool HasHqlVariable(SqlString value)
29+
{
30+
return value.IndexOfOrdinal(HqlVariablePrefix) >= 0;
31+
}
32+
33+
internal static bool IsHqlVariable(string value)
34+
{
35+
return value.StartsWith(HqlVariablePrefix, StringComparison.Ordinal);
1736
}
1837
}
19-
}
38+
}

src/NHibernate/Impl/SessionImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2034,7 +2034,7 @@ public override IDictionary<string, IFilter> EnabledFilters
20342034

20352035
private string[] ParseFilterParameterName(string filterParameterName)
20362036
{
2037-
int dot = filterParameterName.IndexOf(".");
2037+
int dot = filterParameterName.IndexOf('.');
20382038
if (dot <= 0)
20392039
{
20402040
throw new ArgumentException("Invalid filter-parameter name format", "filterParameterName");

src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,9 @@ private string GetWholeAssociationPath(CriteriaImpl.Subcriteria subcriteria)
344344
// some messy, complex stuff here, since createCriteria() can take an
345345
// aliased path, or a path rooted at the creating criteria instance
346346
ICriteria parent = null;
347-
if (path.IndexOf('.') > 0)
347+
if (StringHelper.IsNotRoot(path, out var testAlias))
348348
{
349349
// if it is a compound path
350-
string testAlias = StringHelper.Root(path);
351350
if (!testAlias.Equals(subcriteria.Alias))
352351
{
353352
// and the qualifier is not the alias of this criteria
@@ -678,9 +677,8 @@ private Persister.Entity.IPropertyMapping GetPropertyMapping(string entityName)
678677

679678
public string GetEntityName(ICriteria subcriteria, string propertyName)
680679
{
681-
if (propertyName.IndexOf('.') > 0)
680+
if (StringHelper.IsNotRoot(propertyName, out var root))
682681
{
683-
string root = StringHelper.Root(propertyName);
684682
ICriteria crit = GetAliasedCriteria(root);
685683
if (crit != null)
686684
{
@@ -692,9 +690,8 @@ public string GetEntityName(ICriteria subcriteria, string propertyName)
692690

693691
public string GetSQLAlias(ICriteria criteria, string propertyName)
694692
{
695-
if (propertyName.IndexOf('.') > 0)
693+
if (StringHelper.IsNotRoot(propertyName, out var root))
696694
{
697-
string root = StringHelper.Root(propertyName);
698695
ICriteria subcriteria = GetAliasedCriteria(root);
699696
if (subcriteria != null)
700697
{
@@ -706,9 +703,8 @@ public string GetSQLAlias(ICriteria criteria, string propertyName)
706703

707704
public string GetPropertyName(string propertyName)
708705
{
709-
if (propertyName.IndexOf('.') > 0)
706+
if (StringHelper.IsNotRoot(propertyName, out var root))
710707
{
711-
string root = StringHelper.Root(propertyName);
712708
ICriteria crit = GetAliasedCriteria(root);
713709
if (crit != null)
714710
{

src/NHibernate/Loader/Loader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,7 +1770,7 @@ protected void AdjustQueryParametersForSubSelectFetching(SqlString filteredSqlSt
17701770
protected SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollection<IParameterSpecification> parameterSpecs, ISessionImplementor session)
17711771
{
17721772
var enabledFilters = session.EnabledFilters;
1773-
if (enabledFilters.Count == 0 || sqlString.ToString().IndexOf(ParserHelper.HqlVariablePrefix) < 0)
1773+
if (enabledFilters.Count == 0 || !ParserHelper.HasHqlVariable(sqlString))
17741774
{
17751775
return sqlString;
17761776
}
@@ -1793,7 +1793,7 @@ protected SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollecti
17931793

17941794
foreach (string token in tokens)
17951795
{
1796-
if (token.StartsWith(ParserHelper.HqlVariablePrefix))
1796+
if (ParserHelper.IsHqlVariable(token))
17971797
{
17981798
string filterParameterName = token.Substring(1);
17991799
string[] parts = StringHelper.ParseFilterParameterName(filterParameterName);

src/NHibernate/SqlCommand/SqlString.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,11 @@ public int IndexOfCaseInsensitive(string text)
404404
return IndexOf(text, 0, _length, StringComparison.InvariantCultureIgnoreCase);
405405
}
406406

407+
internal int IndexOfOrdinal(string text)
408+
{
409+
return IndexOf(text, 0, _length, StringComparison.Ordinal);
410+
}
411+
407412
/// <summary>
408413
/// Returns the index of the first occurrence of <paramref name="text" />, case-insensitive.
409414
/// </summary>

0 commit comments

Comments
 (0)