Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit c2257fc

Browse files
committed
Add ComputeHash API to SqlExpression
1 parent e8ef245 commit c2257fc

File tree

1 file changed

+104
-29
lines changed

1 file changed

+104
-29
lines changed

src/ServiceStack.OrmLite/Expressions/SqlExpression.cs

Lines changed: 104 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
using System.Reflection;
88
using System.Text;
99
using System.Linq.Expressions;
10-
using System.Runtime.CompilerServices;
1110
using System.Text.RegularExpressions;
12-
using ServiceStack.OrmLite.Converters;
13-
using ServiceStack.OrmLite.Dapper;
1411
using ServiceStack.Text;
1512

1613
namespace ServiceStack.OrmLite
@@ -20,9 +17,6 @@ public abstract partial class SqlExpression<T> : ISqlExpression, IHasUntypedSqlE
2017
public const string TrueLiteral = "(1=1)";
2118
public const string FalseLiteral = "(1=0)";
2219

23-
protected bool visitedExpressionIsTableColumn = false;
24-
protected bool skipParameterizationForThisExpression = false;
25-
2620
private Expression<Func<T, bool>> underlyingExpression;
2721
private List<string> orderByProperties = new List<string>();
2822
private string selectExpression = string.Empty;
@@ -37,20 +31,25 @@ public abstract partial class SqlExpression<T> : ISqlExpression, IHasUntypedSqlE
3731
public List<string> InsertFields { get; set; }
3832

3933
private string sep = string.Empty;
40-
protected bool useFieldName = false;
41-
protected bool selectDistinct = false;
42-
protected bool CustomSelect { get; set; }
4334
protected ModelDefinition modelDef;
44-
public bool PrefixFieldWithTableName { get; set; }
4535
public string TableAlias { get; set; }
46-
public bool WhereStatementWithoutWhereString { get; set; }
4736
public IOrmLiteDialectProvider DialectProvider { get; set; }
4837
public List<IDbDataParameter> Params { get; set; }
4938
public Func<string,string> SqlFilter { get; set; }
5039
public static Action<SqlExpression<T>> SelectFilter { get; set; }
5140
public int? Rows { get; set; }
5241
public int? Offset { get; set; }
42+
public bool PrefixFieldWithTableName { get; set; }
5343
public bool UseSelectPropertiesAsAliases { get; set; }
44+
public bool WhereStatementWithoutWhereString { get; set; }
45+
46+
protected bool CustomSelect { get; set; }
47+
protected bool useFieldName = false;
48+
protected bool selectDistinct = false;
49+
protected bool visitedExpressionIsTableColumn = false;
50+
protected bool skipParameterizationForThisExpression = false;
51+
private bool hasEnsureConditions = false;
52+
private bool inSqlMethodCall = false;
5453

5554
protected string Sep => sep;
5655

@@ -81,36 +80,114 @@ public SqlExpression<T> Clone()
8180

8281
protected virtual SqlExpression<T> CopyTo(SqlExpression<T> to)
8382
{
84-
to.visitedExpressionIsTableColumn = visitedExpressionIsTableColumn;
85-
to.skipParameterizationForThisExpression = skipParameterizationForThisExpression;
86-
to.underlyingExpression = underlyingExpression;
87-
to.orderByProperties = orderByProperties;
83+
to.modelDef = modelDef;
84+
to.tableDefs = tableDefs;
85+
8886
to.selectExpression = selectExpression;
87+
to.OnlyFields = OnlyFields != null ? new HashSet<string>(OnlyFields, StringComparer.OrdinalIgnoreCase) : null;
88+
89+
to.UpdateFields = UpdateFields;
90+
to.InsertFields = InsertFields;
91+
92+
to.TableAlias = TableAlias;
8993
to.fromExpression = fromExpression;
9094
to.whereExpression = whereExpression;
9195
to.groupBy = groupBy;
9296
to.havingExpression = havingExpression;
9397
to.orderBy = orderBy;
94-
to.OnlyFields = OnlyFields != null ? new HashSet<string>(OnlyFields, StringComparer.OrdinalIgnoreCase) : null;
95-
to.UpdateFields = UpdateFields;
96-
to.InsertFields = InsertFields;
97-
to.useFieldName = useFieldName;
98-
to.selectDistinct = selectDistinct;
98+
to.orderByProperties = orderByProperties;
99+
100+
to.Offset = Offset;
101+
to.Rows = Rows;
102+
99103
to.CustomSelect = CustomSelect;
100-
to.modelDef = modelDef;
101104
to.PrefixFieldWithTableName = PrefixFieldWithTableName;
102-
to.TableAlias = TableAlias;
105+
to.useFieldName = useFieldName;
106+
to.selectDistinct = selectDistinct;
103107
to.WhereStatementWithoutWhereString = WhereStatementWithoutWhereString;
104-
to.Params = new List<IDbDataParameter>(Params);
105-
to.SqlFilter = SqlFilter;
106-
to.Offset = Offset;
107-
to.Rows = Rows;
108-
to.tableDefs = tableDefs;
108+
to.visitedExpressionIsTableColumn = visitedExpressionIsTableColumn;
109+
to.skipParameterizationForThisExpression = skipParameterizationForThisExpression;
109110
to.UseSelectPropertiesAsAliases = UseSelectPropertiesAsAliases;
110111
to.hasEnsureConditions = hasEnsureConditions;
112+
113+
to.Params = new List<IDbDataParameter>(Params);
114+
115+
to.underlyingExpression = underlyingExpression;
116+
to.SqlFilter = SqlFilter;
117+
111118
return to;
112119
}
113120

121+
/// <summary>
122+
/// Generate a unique SHA1 hash of expression with param values for caching
123+
/// </summary>
124+
public string ComputeHash()
125+
{
126+
var sb = StringBuilderCache.Allocate();
127+
128+
if (!string.IsNullOrEmpty(SelectExpression))
129+
sb.AppendLine(SelectExpression);
130+
if (!OnlyFields.IsEmpty())
131+
sb.AppendLine(OnlyFields.Join(","));
132+
133+
if (!UpdateFields.IsEmpty())
134+
sb.AppendLine(UpdateFields.Join(","));
135+
if (!InsertFields.IsEmpty())
136+
sb.AppendLine(InsertFields.Join(","));
137+
138+
if (!string.IsNullOrEmpty(TableAlias))
139+
sb.AppendLine(TableAlias);
140+
if (!string.IsNullOrEmpty(fromExpression))
141+
sb.AppendLine(fromExpression);
142+
143+
if (!string.IsNullOrEmpty(whereExpression))
144+
sb.AppendLine(whereExpression);
145+
146+
if (!string.IsNullOrEmpty(groupBy))
147+
sb.AppendLine(groupBy);
148+
149+
if (!string.IsNullOrEmpty(havingExpression))
150+
sb.AppendLine(havingExpression);
151+
152+
if (!string.IsNullOrEmpty(orderBy))
153+
sb.AppendLine(orderBy);
154+
if (!orderByProperties.IsEmpty())
155+
sb.AppendLine(orderByProperties.Join(","));
156+
157+
if (Offset != null || Rows != null)
158+
sb.Append(Offset ?? 0).Append(',').Append(Rows ?? 0).AppendLine();
159+
160+
var flags = 0;
161+
sb.Append("FLAGS=");
162+
sb.Append(CustomSelect ? "1" : "0");
163+
sb.Append(PrefixFieldWithTableName ? "1" : "0");
164+
sb.Append(useFieldName ? "1" : "0");
165+
sb.Append(selectDistinct ? "1" : "0");
166+
sb.Append(WhereStatementWithoutWhereString ? "1" : "0");
167+
sb.Append(visitedExpressionIsTableColumn ? "1" : "0");
168+
sb.Append(skipParameterizationForThisExpression ? "1" : "0");
169+
sb.Append(UseSelectPropertiesAsAliases ? "1" : "0");
170+
sb.Append(hasEnsureConditions ? "1" : "0");
171+
172+
if (Params.Count > 0)
173+
{
174+
sb.AppendLine("PARAMS=");
175+
for (var i = 0; i < Params.Count; i++)
176+
{
177+
sb.AppendLine(Params[i].Value.ConvertTo<string>());
178+
}
179+
sb.AppendLine();
180+
}
181+
182+
var uniqueExpr = StringBuilderCache.ReturnAndFree(sb);
183+
// fastest up to 500 chars https://wintermute79.wordpress.com/2014/10/10/c-sha-1-benchmark/
184+
using var sha1 = new System.Security.Cryptography.SHA1Managed();
185+
var hash = sha1.ComputeHash(Encoding.ASCII.GetBytes(uniqueExpr));
186+
var hexFormat = hash.ToHex();
187+
188+
return hexFormat;
189+
}
190+
114191
/// <summary>
115192
/// Clear select expression. All properties will be selected.
116193
/// </summary>
@@ -621,7 +698,6 @@ protected SqlExpression<T> AppendToEnsure(Expression predicate)
621698
return Ensure(newExpr);
622699
}
623700

624-
private bool hasEnsureConditions = false;
625701
/// <summary>
626702
/// Add a WHERE Condition to always be applied, irrespective of other WHERE conditions
627703
/// </summary>
@@ -2312,7 +2388,6 @@ protected virtual bool IsColumnAccess(MethodCallExpression m)
23122388
&& IsJoinedTable(exp.Expression.Type);
23132389
}
23142390

2315-
private bool inSqlMethodCall = false;
23162391

23172392
protected virtual object VisitMethodCall(MethodCallExpression m)
23182393
{

0 commit comments

Comments
 (0)