Skip to content

Commit 3114ccb

Browse files
committed
Oracle now correctly handles equality operator for byte[] fields
1 parent 93b4245 commit 3114ccb

File tree

3 files changed

+166
-136
lines changed

3 files changed

+166
-136
lines changed

Orm/Xtensive.Orm.Tests/Issues/Issue0587_ByteArrayEquals.cs

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
// Copyright (C) 2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2010-2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Gamzov
55
// Created: 2010.01.22
66

77
using System;
88
using System.Linq;
99
using NUnit.Framework;
1010
using Xtensive.Orm.Configuration;
11-
using Xtensive.Orm.Tests.Issues.Xtensive.Storage.Tests.Issues.Issue0587_ByteArrayEquals_Model;
11+
using Xtensive.Orm.Tests.Issues.Issue0587_ByteArrayEquals_Model;
1212

1313
namespace Xtensive.Orm.Tests.Issues
1414
{
15-
namespace Xtensive.Storage.Tests.Issues.Issue0587_ByteArrayEquals_Model
15+
namespace Issue0587_ByteArrayEquals_Model
1616
{
17-
// [Index("Name", Unique = true)]
18-
// [Index("UniqueIndentifier", Unique = true)]
1917
[HierarchyRoot]
2018
public class User : Entity
2119
{
@@ -34,48 +32,38 @@ public class User : Entity
3432
[Serializable]
3533
public class Issue0587_ByteArrayEquals : AutoBuildTest
3634
{
37-
public override void TestFixtureSetUp()
38-
{
39-
base.TestFixtureSetUp();
40-
using (var session = Domain.OpenSession()) {
41-
using (var t = session.OpenTransaction()) {
42-
Fill();
43-
t.Complete();
44-
}
45-
}
46-
}
47-
48-
private void Fill()
49-
{
50-
for (byte i = 0; i < 10; i++) {
51-
var user = new User {
52-
Name = string.Format("name_{0}", i),
53-
Photo = new byte[] {i, i, i}
54-
};
55-
}
56-
Session.Current.SaveChanges();
57-
}
58-
5935
protected override DomainConfiguration BuildConfiguration()
6036
{
6137
var config = base.BuildConfiguration();
6238
config.Types.Register(typeof (User).Assembly, typeof (User).Namespace);
6339
return config;
6440
}
6541

42+
protected override void PopulateData()
43+
{
44+
using (var session = Domain.OpenSession())
45+
using (var t = session.OpenTransaction()) {
46+
for (byte i = 0; i < 10; i++) {
47+
_ = new User {
48+
Name = string.Format("name_{0}", i),
49+
Photo = new byte[] { i, i, i }
50+
};
51+
}
52+
t.Complete();
53+
}
54+
}
55+
6656
[Test]
6757
public void MainTest()
6858
{
69-
using (var session = Domain.OpenSession()) {
70-
using (var t = session.OpenTransaction()) {
71-
int pageIndex = 1;
72-
int pageSize = 1;
73-
var usersQuery = session.Query.All<User>().Skip(pageIndex * pageSize).Take(pageSize);
74-
var key = new byte[]{1,1,1};
75-
var query = session.Query.All<User>().Where(user => user.Photo==key);
76-
var result = query.ToList();
77-
Assert.Greater(result.Count, 0);
78-
}
59+
using (var session = Domain.OpenSession())
60+
using (var t = session.OpenTransaction()) {
61+
int pageIndex = 1;
62+
int pageSize = 1;
63+
var usersQuery = session.Query.All<User>().Skip(pageIndex * pageSize).Take(pageSize);
64+
var key = new byte[] { 1, 1, 1 };
65+
var result = session.Query.All<User>().Where(user => user.Photo == key).ToList();
66+
Assert.Greater(result.Count, 0);
7967
}
8068
}
8169
}

Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.Helpers.cs

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
55
// Created: 2009.09.26
66

@@ -17,6 +17,15 @@ namespace Xtensive.Orm.Providers
1717
{
1818
partial class ExpressionProcessor
1919
{
20+
private readonly static Type ObjectType = typeof(object);
21+
private readonly static Type BooleanType = typeof(bool);
22+
private readonly static Type Int32Type = typeof(int);
23+
private readonly static Type CharType = typeof(char);
24+
25+
private readonly static Type DateTimeType = typeof(DateTime);
26+
private readonly static Type DateTimeOffsetType = typeof(DateTimeOffset);
27+
private readonly static Type ParameterType = typeof(Parameter);
28+
2029
private SqlExpression TryTranslateCompareExpression(BinaryExpression expression)
2130
{
2231
bool isGoodExpression =
@@ -178,40 +187,50 @@ private SqlExpression TryTranslateInequalitySpecialCases(SqlExpression left, Sql
178187
return null;
179188
}
180189

190+
private (SqlExpression right, SqlExpression left) BuildByteArraySyntaxComparison(SqlExpression left, SqlExpression right)
191+
{
192+
var newLeft = (SqlExpression) SqlDml.Literal(0);
193+
var newRight = OracleBlobCompare(left, right);
194+
195+
return (newLeft, newRight);
196+
}
197+
198+
private static SqlExpression OracleBlobCompare(SqlExpression left, SqlExpression right)
199+
{
200+
return SqlDml.FunctionCall("dbms_lob.compare", left, right);
201+
}
202+
181203
private SqlExpression CompileMember(MemberInfo member, SqlExpression instance, params SqlExpression[] arguments)
182204
{
183205
var memberCompiler = memberCompilerProvider.GetCompiler(member);
184206
if (memberCompiler==null)
185207
throw new NotSupportedException(string.Format(Strings.ExMemberXIsNotSupported, member.GetFullName(true)));
186208
return memberCompiler.Invoke(instance, arguments);
187209
}
188-
210+
189211
private static bool IsCharToIntConvert(Expression e)
190212
{
191213
return
192-
e.NodeType==ExpressionType.Convert &&
193-
e.Type==typeof (int) &&
194-
((UnaryExpression) e).Operand.Type==typeof (char);
214+
e.NodeType == ExpressionType.Convert &&
215+
e.Type == Int32Type &&
216+
((UnaryExpression) e).Operand.Type == CharType;
195217
}
196218

197-
private static bool IsIntConstant(Expression expression)
198-
{
199-
return expression.NodeType==ExpressionType.Constant && expression.Type==typeof (int);
200-
}
219+
private static bool IsIntConstant(Expression expression) =>
220+
expression.NodeType == ExpressionType.Constant && expression.Type == Int32Type;
201221

202-
private static bool IsBooleanExpression(Expression expression)
203-
{
204-
return StripObjectCasts(expression).Type.StripNullable()==typeof (bool);
205-
}
222+
private static bool IsBooleanExpression(Expression expression) =>
223+
IsExpressionOf(expression, BooleanType);
206224

207-
private static bool IsDateTimeExpression(Expression expression)
208-
{
209-
return StripObjectCasts(expression).Type.StripNullable()==typeof (DateTime);
210-
}
225+
private static bool IsDateTimeExpression(Expression expression) =>
226+
IsExpressionOf(expression, DateTimeType);
227+
228+
private static bool IsDateTimeOffsetExpression(Expression expression) =>
229+
IsExpressionOf(expression, DateTimeOffsetType);
211230

212-
private static bool IsDateTimeOffsetExpression(Expression expression)
231+
private static bool IsExpressionOf(Expression expression, Type type)
213232
{
214-
return StripObjectCasts(expression).Type.StripNullable()==typeof (DateTimeOffset);
233+
return StripObjectCasts(expression).Type.StripNullable() == type;
215234
}
216235

217236
private static bool IsComparisonExpression(Expression expression)
@@ -227,8 +246,9 @@ private static bool IsComparisonExpression(Expression expression)
227246

228247
private static Expression StripObjectCasts(Expression expression)
229248
{
230-
while (expression.Type==typeof (object) && expression.NodeType==ExpressionType.Convert)
249+
while (expression.Type == ObjectType && expression.NodeType == ExpressionType.Convert) {
231250
expression = GetOperand(expression);
251+
}
232252
return expression;
233253
}
234254

@@ -262,33 +282,37 @@ private QueryParameterIdentity GetParameterIdentity(TypeMapping mapping,
262282
var expression = accessor.Body;
263283

264284
// Strip cast to object
265-
if (expression.NodeType==ExpressionType.Convert)
285+
if (expression.NodeType == ExpressionType.Convert) {
266286
expression = ((UnaryExpression) expression).Operand;
287+
}
267288

268289
// Check for closure member access
269-
if (expression.NodeType!=ExpressionType.MemberAccess)
290+
if (expression.NodeType != ExpressionType.MemberAccess) {
270291
return null;
292+
}
271293

272294
var memberAccess = (MemberExpression) expression;
273295
var operand = memberAccess.Expression;
274-
if (operand==null || !operand.Type.IsClosure())
296+
if (operand == null || !operand.Type.IsClosure()) {
275297
return null;
298+
}
299+
276300
var fieldName = memberAccess.Member.Name;
277301

278302
// Check for raw closure
279-
if (operand.NodeType==ExpressionType.Constant) {
303+
if (operand.NodeType == ExpressionType.Constant) {
280304
var closureObject = ((ConstantExpression) operand).Value;
281305
return new QueryParameterIdentity(mapping, closureObject, fieldName, bindingType);
282306
}
283307

284308
// Check for parameterized closure
285-
if (operand.NodeType==ExpressionType.MemberAccess) {
309+
if (operand.NodeType == ExpressionType.MemberAccess) {
286310
memberAccess = (MemberExpression) operand;
287311
operand = memberAccess.Expression;
288-
var isParameter = operand!=null
289-
&& operand.NodeType==ExpressionType.Constant
290-
&& typeof (Parameter).IsAssignableFrom(operand.Type)
291-
&& memberAccess.Member.Name=="Value";
312+
var isParameter = operand != null
313+
&& operand.NodeType == ExpressionType.Constant
314+
&& ParameterType.IsAssignableFrom(operand.Type)
315+
&& memberAccess.Member.Name == "Value";
292316
if (isParameter) {
293317
var parameterObject = ((ConstantExpression) operand).Value;
294318
return new QueryParameterIdentity(mapping, parameterObject, fieldName, bindingType);

0 commit comments

Comments
 (0)