77using System . Reflection ;
88using System . Text ;
99using System . Linq . Expressions ;
10- using System . Runtime . CompilerServices ;
1110using System . Text . RegularExpressions ;
12- using ServiceStack . OrmLite . Converters ;
13- using ServiceStack . OrmLite . Dapper ;
1411using ServiceStack . Text ;
1512
1613namespace 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