Skip to content

Commit f5cc06e

Browse files
committed
Merge pull request #280 from amroel/NH-3630
NH-3630 - Add bitwise operation support for dialects using internal/external functions
2 parents d9ce463 + ed66ffb commit f5cc06e

File tree

11 files changed

+484
-169
lines changed

11 files changed

+484
-169
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System;
2+
using System.Collections;
3+
using NHibernate.Dialect.Function;
4+
using NHibernate.Engine;
5+
using NHibernate.SqlCommand;
6+
using NHibernate.Type;
7+
8+
namespace NHibernate.Dialect
9+
{
10+
/// <summary>
11+
/// Treats bitwise operations as SQL function calls.
12+
/// </summary>
13+
[Serializable]
14+
public class BitwiseFunctionOperation : ISQLFunction
15+
{
16+
private readonly string _functionName;
17+
private SqlStringBuilder _sqlBuffer;
18+
private Queue _args;
19+
20+
/// <summary>
21+
/// Creates an instance of this class using the provided function name
22+
/// </summary>
23+
/// <param name="functionName">
24+
/// The bitwise function name as defined by the SQL-Dialect
25+
/// </param>
26+
public BitwiseFunctionOperation(string functionName)
27+
{
28+
_functionName = functionName;
29+
}
30+
31+
#region ISQLFunction Members
32+
33+
public IType ReturnType(IType columnType, IMapping mapping)
34+
{
35+
return NHibernateUtil.Int64;
36+
}
37+
38+
public bool HasArguments
39+
{
40+
get { return true; }
41+
}
42+
43+
public bool HasParenthesesIfNoArguments
44+
{
45+
get { return true; }
46+
}
47+
48+
public SqlString Render(IList args, ISessionFactoryImplementor factory)
49+
{
50+
Prepare(args);
51+
52+
AddFunctionName();
53+
OpenParens();
54+
AddArguments();
55+
CloseParens();
56+
57+
return SqlResult();
58+
}
59+
60+
#endregion
61+
62+
private void Prepare(IList args)
63+
{
64+
_sqlBuffer = new SqlStringBuilder();
65+
_args = new Queue();
66+
foreach (var arg in args)
67+
{
68+
if (!IsParens(arg.ToString()))
69+
_args.Enqueue(arg);
70+
}
71+
}
72+
73+
private static bool IsParens(string candidate)
74+
{
75+
return candidate == "(" || candidate == ")";
76+
}
77+
78+
private void AddFunctionName()
79+
{
80+
_sqlBuffer.Add(_functionName);
81+
}
82+
83+
private void OpenParens()
84+
{
85+
_sqlBuffer.Add("(");
86+
}
87+
88+
private void AddArguments()
89+
{
90+
while (_args.Count > 0)
91+
{
92+
var arg = _args.Dequeue();
93+
if (arg is Parameter || arg is SqlString)
94+
_sqlBuffer.AddObject(arg);
95+
else
96+
_sqlBuffer.Add(arg.ToString());
97+
if (_args.Count > 0)
98+
_sqlBuffer.Add(", ");
99+
}
100+
}
101+
102+
private void CloseParens()
103+
{
104+
_sqlBuffer.Add(")");
105+
}
106+
107+
private SqlString SqlResult()
108+
{
109+
return _sqlBuffer.ToSqlString();
110+
}
111+
}
112+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System;
2+
using System.Collections;
3+
using NHibernate.Dialect.Function;
4+
using NHibernate.Engine;
5+
using NHibernate.SqlCommand;
6+
using NHibernate.Type;
7+
8+
namespace NHibernate.Dialect
9+
{
10+
/// <summary>
11+
/// Treats bitwise operations as native operations.
12+
/// </summary>
13+
/// </remarks>
14+
[Serializable]
15+
public class BitwiseNativeOperation : ISQLFunction
16+
{
17+
private readonly string _sqlOpToken;
18+
private readonly bool _isNot;
19+
private Queue _args;
20+
private SqlStringBuilder _sqlBuffer;
21+
22+
/// <summary>
23+
/// creates an instance using the giving token
24+
/// </summary>
25+
/// <param name="sqlOpToken">
26+
/// The operation token
27+
/// </param>
28+
/// <remarks>
29+
/// Use this constructor only if the token DOES NOT represent a NOT-Operation
30+
/// </remarks>
31+
public BitwiseNativeOperation(string sqlOpToken)
32+
: this(sqlOpToken, false)
33+
{
34+
}
35+
36+
/// <summary>
37+
/// creates an instance using the giving token and the flag indicating a NOT-Operation
38+
/// </summary>
39+
/// <param name="sqlOpToken"></param>
40+
/// <param name="isNot"></param>
41+
public BitwiseNativeOperation(string sqlOpToken, bool isNot)
42+
{
43+
_sqlOpToken = sqlOpToken;
44+
_isNot = isNot;
45+
}
46+
47+
#region ISQLFunction Members
48+
49+
public IType ReturnType(IType columnType, IMapping mapping)
50+
{
51+
return NHibernateUtil.Int64;
52+
}
53+
54+
public bool HasArguments
55+
{
56+
get { return true; }
57+
}
58+
59+
public bool HasParenthesesIfNoArguments
60+
{
61+
get { return false; }
62+
}
63+
64+
public SqlString Render(IList args, ISessionFactoryImplementor factory)
65+
{
66+
Prepare(args);
67+
if (_isNot == false)
68+
AddFirstArgument();
69+
AddToken();
70+
AddRestOfArguments();
71+
72+
return _sqlBuffer.ToSqlString();
73+
}
74+
75+
#endregion
76+
77+
private void Prepare(IList args)
78+
{
79+
_sqlBuffer = new SqlStringBuilder();
80+
_args = new Queue(args);
81+
}
82+
83+
private void AddFirstArgument()
84+
{
85+
AddToBuffer(_args.Dequeue());
86+
}
87+
88+
private void AddToken()
89+
{
90+
AddToBuffer(string.Format(" {0} ", _sqlOpToken));
91+
}
92+
93+
private void AddRestOfArguments()
94+
{
95+
while (_args.Count > 0)
96+
{
97+
AddToBuffer(_args.Dequeue());
98+
}
99+
}
100+
101+
private void AddToBuffer(object arg)
102+
{
103+
if (arg is Parameter || arg is SqlString)
104+
_sqlBuffer.AddObject(arg);
105+
else
106+
_sqlBuffer.Add(arg.ToString());
107+
}
108+
}
109+
}

src/NHibernate/Dialect/Dialect.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ protected Dialect()
113113
RegisterFunction("month", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(month from ?1)"));
114114
RegisterFunction("year", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(year from ?1)"));
115115

116+
// Bitwise operations
117+
RegisterFunction("band", new BitwiseNativeOperation("&"));
118+
RegisterFunction("bor", new BitwiseNativeOperation("|"));
119+
RegisterFunction("bxor", new BitwiseNativeOperation("^"));
120+
RegisterFunction("bnot", new BitwiseNativeOperation("~", true));
121+
116122
RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as char)"));
117123

118124
// register hibernate types for default use in scalar sqlquery type auto detection

src/NHibernate/Dialect/FirebirdDialect.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,11 @@ private void OverrideStandardHQLFunctions()
322322
RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as VARCHAR(255))"));
323323
RegisterFunction("sysdate", new CastedFunction("today", NHibernateUtil.Date));
324324
RegisterFunction("date", new SQLFunctionTemplate(NHibernateUtil.Date, "cast(?1 as date)"));
325+
// Bitwise operations
326+
RegisterFunction("band", new BitwiseFunctionOperation("bin_and"));
327+
RegisterFunction("bor", new BitwiseFunctionOperation("bin_or"));
328+
RegisterFunction("bxor", new BitwiseFunctionOperation("bin_xor"));
329+
RegisterFunction("bnot", new BitwiseFunctionOperation("bin_not"));
325330
}
326331

327332
private void RegisterFirebirdServerEmbeddedFunctions()
@@ -349,9 +354,6 @@ private void RegisterExternalFbAndIbStandardUDFs()
349354
private void RegisterMathematicalFunctions()
350355
{
351356
RegisterFunction("abs", new StandardSQLFunction("abs", NHibernateUtil.Double));
352-
RegisterFunction("bin_and", new StandardSQLFunction("bin_and", NHibernateUtil.Int32));
353-
RegisterFunction("bin_or", new StandardSQLFunction("bin_or", NHibernateUtil.Int32));
354-
RegisterFunction("bin_xor", new StandardSQLFunction("bin_xor", NHibernateUtil.Int32));
355357
RegisterFunction("ceiling", new StandardSQLFunction("ceiling", NHibernateUtil.Double));
356358
RegisterFunction("div", new StandardSQLFunction("div", NHibernateUtil.Double));
357359
RegisterFunction("dpower", new StandardSQLFunction("dpower", NHibernateUtil.Double));

src/NHibernate/Hql/Ast/ANTLR/Generated/HqlLexer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// </auto-generated>
99
//------------------------------------------------------------------------------
1010

11-
// $ANTLR 3.5.0.2 Hql.g 2014-08-03 19:45:41
11+
// $ANTLR 3.5.0.2 Hql.g 2015-02-24 17:27:14
1212

1313
// The variable 'variable' is assigned but its value is never used.
1414
#pragma warning disable 219

src/NHibernate/Hql/Ast/ANTLR/Generated/HqlParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// </auto-generated>
99
//------------------------------------------------------------------------------
1010

11-
// $ANTLR 3.5.0.2 Hql.g 2014-08-03 19:45:40
11+
// $ANTLR 3.5.0.2 Hql.g 2015-02-24 17:27:14
1212

1313
// The variable 'variable' is assigned but its value is never used.
1414
#pragma warning disable 219

src/NHibernate/Hql/Ast/ANTLR/Generated/HqlSqlWalker.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// </auto-generated>
99
//------------------------------------------------------------------------------
1010

11-
// $ANTLR 3.5.0.2 HqlSqlWalker.g 2014-10-10 11:16:23
11+
// $ANTLR 3.5.0.2 HqlSqlWalker.g 2015-02-24 17:27:15
1212

1313
// The variable 'variable' is assigned but its value is never used.
1414
#pragma warning disable 219
@@ -2585,7 +2585,7 @@ private AstTreeRuleReturnScope<IASTNode, IASTNode> orderExpr()
25852585
partial void EnterRule_resultVariableRef();
25862586
partial void LeaveRule_resultVariableRef();
25872587
// $ANTLR start "resultVariableRef"
2588-
// HqlSqlWalker.g:158:1: resultVariableRef : i= identifier -> ^( RESULT_VARIABLE_REF[$i.start.ToString()] ) ;
2588+
// HqlSqlWalker.g:158:1: resultVariableRef : i= identifier -> ^( RESULT_VARIABLE_REF[$i.tree.Text] ) ;
25892589
[GrammarRule("resultVariableRef")]
25902590
private AstTreeRuleReturnScope<IASTNode, IASTNode> resultVariableRef()
25912591
{
@@ -2607,7 +2607,7 @@ private AstTreeRuleReturnScope<IASTNode, IASTNode> resultVariableRef()
26072607
DebugLocation(158, 1);
26082608
try
26092609
{
2610-
// HqlSqlWalker.g:162:2: (i= identifier -> ^( RESULT_VARIABLE_REF[$i.start.ToString()] ) )
2610+
// HqlSqlWalker.g:162:2: (i= identifier -> ^( RESULT_VARIABLE_REF[$i.tree.Text] ) )
26112611
DebugEnterAlt(1);
26122612
// HqlSqlWalker.g:162:4: i= identifier
26132613
{
@@ -2632,14 +2632,14 @@ private AstTreeRuleReturnScope<IASTNode, IASTNode> resultVariableRef()
26322632
RewriteRuleSubtreeStream stream_retval=new RewriteRuleSubtreeStream(adaptor,"rule retval",retval!=null?retval.Tree:null);
26332633

26342634
root_0 = (IASTNode)adaptor.Nil();
2635-
// 163:2: -> ^( RESULT_VARIABLE_REF[$i.start.ToString()] )
2635+
// 163:2: -> ^( RESULT_VARIABLE_REF[$i.tree.Text] )
26362636
{
26372637
DebugLocation(163, 5);
2638-
// HqlSqlWalker.g:163:5: ^( RESULT_VARIABLE_REF[$i.start.ToString()] )
2638+
// HqlSqlWalker.g:163:5: ^( RESULT_VARIABLE_REF[$i.tree.Text] )
26392639
{
26402640
IASTNode root_1 = (IASTNode)adaptor.Nil();
26412641
DebugLocation(163, 7);
2642-
root_1 = (IASTNode)adaptor.BecomeRoot((IASTNode)adaptor.Create(RESULT_VARIABLE_REF, (i!=null?((IASTNode)i.Start):default(IASTNode)).ToString()), root_1);
2642+
root_1 = (IASTNode)adaptor.BecomeRoot((IASTNode)adaptor.Create(RESULT_VARIABLE_REF, (i!=null?((IASTNode)i.Tree):default(IASTNode)).Text), root_1);
26432643

26442644
adaptor.AddChild(root_0, root_1);
26452645
}

0 commit comments

Comments
 (0)