Skip to content

NH-3630 - Add bitwise operation support for dialects using internal/external functions #280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/NHibernate/Dialect/BitwiseFunctionOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Collections;
using NHibernate.Dialect.Function;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using NHibernate.Type;

namespace NHibernate.Dialect
{
/// <summary>
/// Treats bitwise operations as SQL function calls.
/// </summary>
[Serializable]
public class BitwiseFunctionOperation : ISQLFunction
{
private readonly string _functionName;
private SqlStringBuilder _sqlBuffer;
private Queue _args;

/// <summary>
/// Creates an instance of this class using the provided function name
/// </summary>
/// <param name="functionName">
/// The bitwise function name as defined by the SQL-Dialect
/// </param>
public BitwiseFunctionOperation(string functionName)
{
_functionName = functionName;
}

#region ISQLFunction Members

public IType ReturnType(IType columnType, IMapping mapping)
{
return NHibernateUtil.Int64;
}

public bool HasArguments
{
get { return true; }
}

public bool HasParenthesesIfNoArguments
{
get { return true; }
}

public SqlString Render(IList args, ISessionFactoryImplementor factory)
{
Prepare(args);

AddFunctionName();
OpenParens();
AddArguments();
CloseParens();

return SqlResult();
}

#endregion

private void Prepare(IList args)
{
_sqlBuffer = new SqlStringBuilder();
_args = new Queue();
foreach (var arg in args)
{
if (!IsParens(arg.ToString()))
_args.Enqueue(arg);
}
}

private static bool IsParens(string candidate)
{
return candidate == "(" || candidate == ")";
}

private void AddFunctionName()
{
_sqlBuffer.Add(_functionName);
}

private void OpenParens()
{
_sqlBuffer.Add("(");
}

private void AddArguments()
{
while (_args.Count > 0)
{
var arg = _args.Dequeue();
if (arg is Parameter || arg is SqlString)
_sqlBuffer.AddObject(arg);
else
_sqlBuffer.Add(arg.ToString());
if (_args.Count > 0)
_sqlBuffer.Add(", ");
}
}

private void CloseParens()
{
_sqlBuffer.Add(")");
}

private SqlString SqlResult()
{
return _sqlBuffer.ToSqlString();
}
}
}
109 changes: 109 additions & 0 deletions src/NHibernate/Dialect/BitwiseNativeOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System;
using System.Collections;
using NHibernate.Dialect.Function;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using NHibernate.Type;

namespace NHibernate.Dialect
{
/// <summary>
/// Treats bitwise operations as native operations.
/// </summary>
/// </remarks>
[Serializable]
public class BitwiseNativeOperation : ISQLFunction
{
private readonly string _sqlOpToken;
private readonly bool _isNot;
private Queue _args;
private SqlStringBuilder _sqlBuffer;

/// <summary>
/// creates an instance using the giving token
/// </summary>
/// <param name="sqlOpToken">
/// The operation token
/// </param>
/// <remarks>
/// Use this constructor only if the token DOES NOT represent a NOT-Operation
/// </remarks>
public BitwiseNativeOperation(string sqlOpToken)
: this(sqlOpToken, false)
{
}

/// <summary>
/// creates an instance using the giving token and the flag indicating a NOT-Operation
/// </summary>
/// <param name="sqlOpToken"></param>
/// <param name="isNot"></param>
public BitwiseNativeOperation(string sqlOpToken, bool isNot)
{
_sqlOpToken = sqlOpToken;
_isNot = isNot;
}

#region ISQLFunction Members

public IType ReturnType(IType columnType, IMapping mapping)
{
return NHibernateUtil.Int64;
}

public bool HasArguments
{
get { return true; }
}

public bool HasParenthesesIfNoArguments
{
get { return false; }
}

public SqlString Render(IList args, ISessionFactoryImplementor factory)
{
Prepare(args);
if (_isNot == false)
AddFirstArgument();
AddToken();
AddRestOfArguments();

return _sqlBuffer.ToSqlString();
}

#endregion

private void Prepare(IList args)
{
_sqlBuffer = new SqlStringBuilder();
_args = new Queue(args);
}

private void AddFirstArgument()
{
AddToBuffer(_args.Dequeue());
}

private void AddToken()
{
AddToBuffer(string.Format(" {0} ", _sqlOpToken));
}

private void AddRestOfArguments()
{
while (_args.Count > 0)
{
AddToBuffer(_args.Dequeue());
}
}

private void AddToBuffer(object arg)
{
if (arg is Parameter || arg is SqlString)
_sqlBuffer.AddObject(arg);
else
_sqlBuffer.Add(arg.ToString());
}
}
}
6 changes: 6 additions & 0 deletions src/NHibernate/Dialect/Dialect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ protected Dialect()
RegisterFunction("month", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(month from ?1)"));
RegisterFunction("year", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(year from ?1)"));

// Bitwise operations
RegisterFunction("band", new BitwiseNativeOperation("&"));
RegisterFunction("bor", new BitwiseNativeOperation("|"));
RegisterFunction("bxor", new BitwiseNativeOperation("^"));
RegisterFunction("bnot", new BitwiseNativeOperation("~", true));

RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as char)"));

// register hibernate types for default use in scalar sqlquery type auto detection
Expand Down
8 changes: 5 additions & 3 deletions src/NHibernate/Dialect/FirebirdDialect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ private void OverrideStandardHQLFunctions()
RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as VARCHAR(255))"));
RegisterFunction("sysdate", new CastedFunction("today", NHibernateUtil.Date));
RegisterFunction("date", new SQLFunctionTemplate(NHibernateUtil.Date, "cast(?1 as date)"));
// Bitwise operations
RegisterFunction("band", new BitwiseFunctionOperation("bin_and"));
RegisterFunction("bor", new BitwiseFunctionOperation("bin_or"));
RegisterFunction("bxor", new BitwiseFunctionOperation("bin_xor"));
RegisterFunction("bnot", new BitwiseFunctionOperation("bin_not"));
}

private void RegisterFirebirdServerEmbeddedFunctions()
Expand Down Expand Up @@ -349,9 +354,6 @@ private void RegisterExternalFbAndIbStandardUDFs()
private void RegisterMathematicalFunctions()
{
RegisterFunction("abs", new StandardSQLFunction("abs", NHibernateUtil.Double));
RegisterFunction("bin_and", new StandardSQLFunction("bin_and", NHibernateUtil.Int32));
RegisterFunction("bin_or", new StandardSQLFunction("bin_or", NHibernateUtil.Int32));
RegisterFunction("bin_xor", new StandardSQLFunction("bin_xor", NHibernateUtil.Int32));
RegisterFunction("ceiling", new StandardSQLFunction("ceiling", NHibernateUtil.Double));
RegisterFunction("div", new StandardSQLFunction("div", NHibernateUtil.Double));
RegisterFunction("dpower", new StandardSQLFunction("dpower", NHibernateUtil.Double));
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Hql/Ast/ANTLR/Generated/HqlLexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------

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

// The variable 'variable' is assigned but its value is never used.
#pragma warning disable 219
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Hql/Ast/ANTLR/Generated/HqlParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------

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

// The variable 'variable' is assigned but its value is never used.
#pragma warning disable 219
Expand Down
12 changes: 6 additions & 6 deletions src/NHibernate/Hql/Ast/ANTLR/Generated/HqlSqlWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------

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

// The variable 'variable' is assigned but its value is never used.
#pragma warning disable 219
Expand Down Expand Up @@ -2585,7 +2585,7 @@ private AstTreeRuleReturnScope<IASTNode, IASTNode> orderExpr()
partial void EnterRule_resultVariableRef();
partial void LeaveRule_resultVariableRef();
// $ANTLR start "resultVariableRef"
// HqlSqlWalker.g:158:1: resultVariableRef : i= identifier -> ^( RESULT_VARIABLE_REF[$i.start.ToString()] ) ;
// HqlSqlWalker.g:158:1: resultVariableRef : i= identifier -> ^( RESULT_VARIABLE_REF[$i.tree.Text] ) ;
[GrammarRule("resultVariableRef")]
private AstTreeRuleReturnScope<IASTNode, IASTNode> resultVariableRef()
{
Expand All @@ -2607,7 +2607,7 @@ private AstTreeRuleReturnScope<IASTNode, IASTNode> resultVariableRef()
DebugLocation(158, 1);
try
{
// HqlSqlWalker.g:162:2: (i= identifier -> ^( RESULT_VARIABLE_REF[$i.start.ToString()] ) )
// HqlSqlWalker.g:162:2: (i= identifier -> ^( RESULT_VARIABLE_REF[$i.tree.Text] ) )
DebugEnterAlt(1);
// HqlSqlWalker.g:162:4: i= identifier
{
Expand All @@ -2632,14 +2632,14 @@ private AstTreeRuleReturnScope<IASTNode, IASTNode> resultVariableRef()
RewriteRuleSubtreeStream stream_retval=new RewriteRuleSubtreeStream(adaptor,"rule retval",retval!=null?retval.Tree:null);

root_0 = (IASTNode)adaptor.Nil();
// 163:2: -> ^( RESULT_VARIABLE_REF[$i.start.ToString()] )
// 163:2: -> ^( RESULT_VARIABLE_REF[$i.tree.Text] )
{
DebugLocation(163, 5);
// HqlSqlWalker.g:163:5: ^( RESULT_VARIABLE_REF[$i.start.ToString()] )
// HqlSqlWalker.g:163:5: ^( RESULT_VARIABLE_REF[$i.tree.Text] )
{
IASTNode root_1 = (IASTNode)adaptor.Nil();
DebugLocation(163, 7);
root_1 = (IASTNode)adaptor.BecomeRoot((IASTNode)adaptor.Create(RESULT_VARIABLE_REF, (i!=null?((IASTNode)i.Start):default(IASTNode)).ToString()), root_1);
root_1 = (IASTNode)adaptor.BecomeRoot((IASTNode)adaptor.Create(RESULT_VARIABLE_REF, (i!=null?((IASTNode)i.Tree):default(IASTNode)).Text), root_1);

adaptor.AddChild(root_0, root_1);
}
Expand Down
Loading