|
From: <ric...@us...> - 2009-10-26 11:02:36
|
Revision: 4802
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4802&view=rev
Author: ricbrown
Date: 2009-10-26 11:02:27 +0000 (Mon, 26 Oct 2009)
Log Message:
-----------
Merge r4801 (Fix NH-847, Stored Procedures support with OracleDataClient)
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs
trunk/nhibernate/src/NHibernate/Driver/IDriver.cs
trunk/nhibernate/src/NHibernate/Driver/OracleClientDriver.cs
trunk/nhibernate/src/NHibernate/Driver/OracleDataClientDriver.cs
trunk/nhibernate/src/NHibernate/Engine/Query/ParamLocationRecognizer.cs
trunk/nhibernate/src/NHibernate/Engine/Query/ParameterMetadata.cs
trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs
trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
trunk/nhibernate/src/NHibernate/Impl/SqlQueryImpl.cs
trunk/nhibernate/src/NHibernate/Loader/Loader.cs
trunk/nhibernate/src/NHibernate/NHibernate.csproj
trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
trunk/nhibernate/src/NHibernate/SqlCommand/SqlCommandInfo.cs
trunk/nhibernate/src/NHibernate.Test/EngineTest/ParameterParserFixture.cs
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/Mappings.hbm.xml
trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/OracleCustomSQLFixture.cs
trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/StoredProcedures.hbm.xml
Added Paths:
-----------
trunk/nhibernate/src/NHibernate/Engine/Query/CallableParser.cs
trunk/nhibernate/src/NHibernate.Test/EngineTest/CallableParserFixture.cs
Modified: trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -136,6 +136,11 @@
return cmd;
}
+ public virtual int RegisterResultSetOutParameter(IDbCommand command, int position, bool hasReturnValue)
+ {
+ throw new NotImplementedException(GetType().Name + " does not support resultsets via stored procedures");
+ }
+
private void SetCommandTimeout(IDbCommand cmd, object envTimeout)
{
if (commandTimeout >= 0)
Modified: trunk/nhibernate/src/NHibernate/Driver/IDriver.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Driver/IDriver.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Driver/IDriver.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -80,6 +80,17 @@
IDbCommand GenerateCommand(CommandType type, SqlString sqlString, SqlType[] parameterTypes);
/// <summary>
+ /// Registers an OUT parameter which will be returing a
+ /// <see cref="IDataReader"/>. How this is accomplished varies greatly
+ /// from DB to DB, hence its inclusion here.
+ /// </summary>
+ /// <param name="command">The <see cref="IDbCommand"/> with CommandType.StoredProcedure.</param>
+ /// <param name="position">The bind position at which to register the OUT param.</param>
+ /// <param name="hasReturnValue">Whether the out parameter is a return value, or an out parameter.</param>
+ /// <returns>The number of (contiguous) bind positions used.</returns>
+ int RegisterResultSetOutParameter(IDbCommand command, int position, bool hasReturnValue);
+
+ /// <summary>
/// Prepare the <paramref name="command" /> by calling <see cref="IDbCommand.Prepare()" />.
/// May be a no-op if the driver does not support preparing commands, or for any other reason.
/// </summary>
Modified: trunk/nhibernate/src/NHibernate/Driver/OracleClientDriver.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Driver/OracleClientDriver.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Driver/OracleClientDriver.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -47,5 +47,12 @@
base.InitializeParameter(dbParam, name, sqlType);
}
}
+
+ public override int RegisterResultSetOutParameter(IDbCommand command, int position, bool hasReturnValue)
+ {
+ throw new System.NotImplementedException(GetType().Name +
+ " does not support resultsets via stored procedures." +
+ " Consider using OracleDataClientDriver instead.");
+ }
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Driver/OracleDataClientDriver.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Driver/OracleDataClientDriver.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Driver/OracleDataClientDriver.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -1,6 +1,8 @@
using System.Data;
+using System.Reflection;
using NHibernate.AdoNet;
using NHibernate.SqlTypes;
+using NHibernate.Util;
namespace NHibernate.Driver
{
@@ -14,7 +16,13 @@
/// </remarks>
public class OracleDataClientDriver : ReflectionBasedDriver, IEmbeddedBatcherFactoryProvider
{
+ private const string driverAssemblyName = "Oracle.DataAccess";
+ private const string connectionTypeName = "Oracle.DataAccess.Client.OracleConnection";
+ private const string commandTypeName = "Oracle.DataAccess.Client.OracleCommand";
private static readonly SqlType GuidSqlType = new SqlType(DbType.Binary, 16);
+ private readonly PropertyInfo oracleDbType;
+ private readonly object oracleDbTypeRefCursor;
+
/// <summary>
/// Initializes a new instance of <see cref="OracleDataClientDriver"/>.
/// </summary>
@@ -23,10 +31,15 @@
/// </exception>
public OracleDataClientDriver()
: base(
- "Oracle.DataAccess",
- "Oracle.DataAccess.Client.OracleConnection",
- "Oracle.DataAccess.Client.OracleCommand")
+ driverAssemblyName,
+ connectionTypeName,
+ commandTypeName)
{
+ System.Type parameterType = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleParameter", driverAssemblyName, false);
+ oracleDbType = parameterType.GetProperty("OracleDbType");
+
+ System.Type oracleDbTypeEnum = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleDbType", driverAssemblyName, false);
+ oracleDbTypeRefCursor = System.Enum.Parse(oracleDbTypeEnum, "RefCursor");
}
/// <summary></summary>
@@ -69,6 +82,19 @@
}
}
+ public override int RegisterResultSetOutParameter(IDbCommand command, int position, bool hasReturnValue)
+ {
+ IDbDataParameter outCursor = command.CreateParameter();
+ outCursor.ParameterName = "";
+ oracleDbType.SetValue(outCursor, oracleDbTypeRefCursor, null);
+
+ outCursor.Direction = hasReturnValue ? ParameterDirection.ReturnValue : ParameterDirection.Output;
+
+ command.Parameters.Insert(position, outCursor);
+
+ return 1;
+ }
+
#region IEmbeddedBatcherFactoryProvider Members
System.Type IEmbeddedBatcherFactoryProvider.BatcherFactoryClass
Added: trunk/nhibernate/src/NHibernate/Engine/Query/CallableParser.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Query/CallableParser.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Engine/Query/CallableParser.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -0,0 +1,33 @@
+using System;
+using System.Text.RegularExpressions;
+using NHibernate.Hql.Classic;
+using NHibernate.Util;
+using NHibernate.SqlCommand;
+
+namespace NHibernate.Engine.Query
+{
+ public static class CallableParser
+ {
+ private static readonly Regex functionNameFinder = new Regex(@"\{[\S\s]*call[\s]+([\w]+)[^\w]");
+ private static readonly int NewLineLength = Environment.NewLine.Length;
+
+ public static SqlString Parse(string sqlString)
+ {
+ bool isCallableSyntax = sqlString.IndexOf("{") == 0 &&
+ sqlString.IndexOf("}") == (sqlString.Length - 1) &&
+ sqlString.IndexOf("call") > 0;
+
+ if (!isCallableSyntax)
+ throw new ParserException("Expected callable syntax {? = call procedure_name[(?, ?, ...)]} but got: " + sqlString);
+
+
+ Match functionMatch = functionNameFinder.Match(sqlString);
+
+ if ((!functionMatch.Success) || (functionMatch.Groups.Count < 2))
+ throw new HibernateException("Could not determine function name for callable SQL: " + sqlString);
+
+ string function = functionMatch.Groups[1].Value;
+ return new SqlString(function);
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Engine/Query/ParamLocationRecognizer.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Query/ParamLocationRecognizer.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Engine/Query/ParamLocationRecognizer.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -13,6 +13,8 @@
private readonly List<int> ordinalParameterLocationList = new List<int>();
+ private bool hasReturnValue = false;
+
/// <summary>
/// Convenience method for creating a param location recognizer and
/// initiating the parse.
@@ -47,11 +49,16 @@
get { return ordinalParameterLocationList; }
}
+ public bool HasReturnValue
+ {
+ get { return hasReturnValue; }
+ }
+
#region IRecognizer Members
public void OutParameter(int position)
{
- // don't care...
+ hasReturnValue = true;
}
public void OrdinalParameter(int position)
Modified: trunk/nhibernate/src/NHibernate/Engine/Query/ParameterMetadata.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Query/ParameterMetadata.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Engine/Query/ParameterMetadata.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -12,8 +12,17 @@
private static readonly OrdinalParameterDescriptor[] EmptyOrdinals = new OrdinalParameterDescriptor[0];
private readonly OrdinalParameterDescriptor[] ordinalDescriptors;
private readonly Dictionary<string, NamedParameterDescriptor> namedDescriptorMap;
+ private readonly bool hasReturnValue = false;
public ParameterMetadata(OrdinalParameterDescriptor[] ordinalDescriptors,
+ IDictionary<string, NamedParameterDescriptor> namedDescriptorMap,
+ bool hasReturnValue)
+ : this (ordinalDescriptors, namedDescriptorMap)
+ {
+ this.hasReturnValue = hasReturnValue;
+ }
+
+ public ParameterMetadata(OrdinalParameterDescriptor[] ordinalDescriptors,
IDictionary<string, NamedParameterDescriptor> namedDescriptorMap)
{
if (ordinalDescriptors == null)
@@ -43,6 +52,11 @@
get { return namedDescriptorMap.Keys; }
}
+ public bool HasReturnValue
+ {
+ get { return hasReturnValue; }
+ }
+
public OrdinalParameterDescriptor GetOrdinalParameterDescriptor(int position)
{
if (position < 1 || position > ordinalDescriptors.Length)
Modified: trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -171,7 +171,7 @@
new NamedParameterDescriptor(name, null, description.BuildPositionsArray(), description.JpaStyle);
}
- return new ParameterMetadata(ordinalDescriptors, namedParamDescriptorMap);
+ return new ParameterMetadata(ordinalDescriptors, namedParamDescriptorMap, recognizer.HasReturnValue);
}
[Serializable]
Modified: trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -279,6 +279,8 @@
public bool Callable { get; set; }
+ public bool HasReturnValue { get; set; }
+
public bool ReadOnly
{
get { return _readOnly; }
Modified: trunk/nhibernate/src/NHibernate/Impl/SqlQueryImpl.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Impl/SqlQueryImpl.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Impl/SqlQueryImpl.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -27,6 +27,7 @@
private readonly IList<INativeSQLQueryReturn> queryReturns;
private readonly ICollection<string> querySpaces;
private readonly bool callable;
+ private readonly bool hasReturnValue;
private bool autoDiscoverTypes;
/// <summary> Constructs a SQLQueryImpl given a sql query defined in the mappings. </summary>
@@ -52,16 +53,9 @@
querySpaces = queryDef.QuerySpaces;
callable = queryDef.IsCallable;
+ hasReturnValue = parameterMetadata.HasReturnValue;
}
- internal SqlQueryImpl(string sql, IList<INativeSQLQueryReturn> queryReturns, ICollection<string> querySpaces, FlushMode flushMode, bool callable, ISessionImplementor session, ParameterMetadata parameterMetadata)
- : base(sql, flushMode, session, parameterMetadata)
- {
- this.queryReturns = queryReturns;
- this.querySpaces = querySpaces;
- this.callable = callable;
- }
-
internal SqlQueryImpl(string sql, string[] returnAliases, System.Type[] returnClasses, LockMode[] lockModes, ISessionImplementor session, ICollection<string> querySpaces, FlushMode flushMode, ParameterMetadata parameterMetadata)
: base(sql, flushMode, session, parameterMetadata)
{
@@ -180,6 +174,7 @@
{
QueryParameters qp = base.GetQueryParameters(namedParams);
qp.Callable = callable;
+ qp.HasReturnValue = hasReturnValue;
qp.HasAutoDiscoverScalarTypes = autoDiscoverTypes;
return qp;
}
Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -11,6 +11,7 @@
using NHibernate.Cache;
using NHibernate.Collection;
using NHibernate.Engine;
+using NHibernate.Engine.Query;
using NHibernate.Event;
using NHibernate.Exceptions;
using NHibernate.Hql.Util;
@@ -1104,7 +1105,8 @@
bool useLimit = UseLimit(selection, dialect);
bool hasFirstRow = GetFirstRow(selection) > 0;
bool useOffset = hasFirstRow && useLimit && dialect.SupportsLimitOffset;
- // TODO NH bool callable = queryParameters.Callable;
+ bool isCallable = queryParameters.Callable;
+ bool hasReturnValue = queryParameters.HasReturnValue;
if (useLimit)
{
@@ -1114,10 +1116,19 @@
sqlString = PreprocessSQL(sqlString, queryParameters, dialect);
- // TODO NH: Callable for SP -> PrepareCallableQueryCommand
- IDbCommand command =
- session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString,
- GetParameterTypes(queryParameters, useLimit, useOffset));
+ IDbCommand command = null;
+ if (isCallable)
+ {
+ command =
+ session.Batcher.PrepareQueryCommand(CommandType.StoredProcedure, CallableParser.Parse(sqlString.ToString()),
+ GetParameterTypes(queryParameters, useLimit, useOffset));
+ }
+ else
+ {
+ command =
+ session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString,
+ GetParameterTypes(queryParameters, useLimit, useOffset));
+ }
try
{
@@ -1133,12 +1144,13 @@
{
colIndex += BindLimitParameters(command, colIndex, selection, session);
}
- // TODO NH
- //if (callable)
- //{
- // colIndex = dialect.RegisterResultSetOutParameter(command, col);
- //}
+ if (isCallable)
+ {
+ colIndex +=
+ session.Factory.ConnectionProvider.Driver.RegisterResultSetOutParameter(command, colIndex, hasReturnValue);
+ }
+
colIndex += BindParameterValues(command, queryParameters, colIndex, session);
if (useLimit && !dialect.BindLimitParametersFirst)
@@ -1263,7 +1275,7 @@
// NH Different behavior:
// The responsibility of parameter binding was entirely moved to QueryParameters
// to deal with positionslParameter+NamedParameter+ParameterOfFilters
- return queryParameters.BindParameters(statement, GetNamedParameterLocs, 0, session);
+ return queryParameters.BindParameters(statement, GetNamedParameterLocs, startIndex, session);
}
public virtual int[] GetNamedParameterLocs(string name)
Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-10-26 11:02:27 UTC (rev 4802)
@@ -524,6 +524,7 @@
<Compile Include="Dialect\SybaseASA9Dialect.cs" />
<Compile Include="Driver\IfxDriver.cs" />
<Compile Include="Driver\OracleLiteDataClientDriver.cs" />
+ <Compile Include="Engine\Query\CallableParser.cs" />
<Compile Include="EntityModeEqualityComparer.cs" />
<Compile Include="Event\AbstractPostDatabaseOperationEvent.cs" />
<Compile Include="Event\AbstractPreDatabaseOperationEvent.cs" />
Modified: trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -3332,20 +3332,20 @@
SqlCommandInfo defaultDelete = GenerateDeleteString(j);
sqlInsertStrings[j] = customSQLInsert[j] != null
- ? new SqlCommandInfo(customSQLInsert[j], defaultInsert.ParameterTypes)
+ ? new SqlCommandInfo(customSQLInsert[j], insertCallable[j], defaultInsert.ParameterTypes)
: defaultInsert;
sqlUpdateStrings[j] = customSQLUpdate[j] != null
- ? new SqlCommandInfo(customSQLUpdate[j], defaultUpdate.ParameterTypes)
+ ? new SqlCommandInfo(customSQLUpdate[j], updateCallable[j], defaultUpdate.ParameterTypes)
: defaultUpdate;
// NH: in practice for lazy update de update sql is the same any way.
sqlLazyUpdateStrings[j] = customSQLUpdate[j] != null
- ? new SqlCommandInfo(customSQLUpdate[j], defaultUpdate.ParameterTypes)
+ ? new SqlCommandInfo(customSQLUpdate[j], updateCallable[j], defaultUpdate.ParameterTypes)
: GenerateUpdateString(NonLazyPropertyUpdateability, j, false);
sqlDeleteStrings[j] = customSQLDelete[j] != null
- ? new SqlCommandInfo(customSQLDelete[j], defaultDelete.ParameterTypes)
+ ? new SqlCommandInfo(customSQLDelete[j], deleteCallable[j], defaultDelete.ParameterTypes)
: defaultDelete;
}
Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlCommandInfo.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/SqlCommand/SqlCommandInfo.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlCommandInfo.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -1,10 +1,12 @@
using System.Data;
+using NHibernate.Engine.Query;
using NHibernate.SqlTypes;
namespace NHibernate.SqlCommand
{
public class SqlCommandInfo
{
+ private readonly CommandType commandType;
private readonly SqlString text;
private readonly SqlType[] parameterTypes;
@@ -12,12 +14,22 @@
{
this.text = text;
this.parameterTypes = parameterTypes;
+ this.commandType = CommandType.Text;
}
+ public SqlCommandInfo(SqlString text, bool isStoredProcedure, SqlType[] parameterTypes)
+ : this(text, parameterTypes)
+ {
+ if (isStoredProcedure)
+ {
+ this.commandType = CommandType.StoredProcedure;
+ this.text = CallableParser.Parse(text.ToString());
+ }
+ }
+
public CommandType CommandType
{
- // Always Text for now
- get { return CommandType.Text; }
+ get { return commandType; }
}
public SqlString Text
Added: trunk/nhibernate/src/NHibernate.Test/EngineTest/CallableParserFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/EngineTest/CallableParserFixture.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/EngineTest/CallableParserFixture.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -0,0 +1,40 @@
+using NUnit.Framework;
+using NHibernate.Engine.Query;
+using NHibernate.SqlCommand;
+using NHibernate.Util;
+
+namespace NHibernate.Test.EngineTest
+{
+ [TestFixture]
+ public class CallableParserFixture
+ {
+ [Test]
+ public void CanFindCallableFunctionName()
+ {
+ string query = @"{ call myFunction(:name) }";
+
+ SqlString sqlFunction = CallableParser.Parse(query);
+ Assert.That(sqlFunction.ToString(), Is.EqualTo("myFunction"));
+ }
+
+ [Test]
+ public void CanDetermineIsNotCallable()
+ {
+ string query = @"SELECT id FROM mytable";
+
+ Assert.Throws<ParserException>(() =>
+ {
+ SqlString sqlFunction = CallableParser.Parse(query);
+ });
+ }
+
+ [Test]
+ public void CanFindCallableFunctionNameWithoutParameters()
+ {
+ string query = @"{ call myFunction }";
+
+ SqlString sqlFunction = CallableParser.Parse(query);
+ Assert.That(sqlFunction.ToString(), Is.EqualTo("myFunction"));
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate.Test/EngineTest/ParameterParserFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/EngineTest/ParameterParserFixture.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate.Test/EngineTest/ParameterParserFixture.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -59,5 +59,22 @@
Assert.DoesNotThrow(() => p = recognizer.NamedParameterDescriptionMap["pizza"]);
}
+ [Test]
+ public void CanRecogniseNoReturnValueParameter()
+ {
+ string query = "{ call myFunction(?) }";
+ ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
+ ParameterParser.Parse(query, recognizer);
+ Assert.That(recognizer.HasReturnValue, Is.False);
+ }
+
+ [Test]
+ public void CanRecogniseReturnValueParameter()
+ {
+ string query = "{ ? = call myFunction(?) }";
+ ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
+ ParameterParser.Parse(query, recognizer);
+ Assert.That(recognizer.HasReturnValue, Is.True);
+ }
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-10-26 11:02:27 UTC (rev 4802)
@@ -165,6 +165,7 @@
<Compile Include="Criteria\Reptile.cs" />
<Compile Include="DriverTest\SqlClientDriverFixture.cs" />
<Compile Include="DriverTest\SqlServerCeDriverFixture.cs" />
+ <Compile Include="EngineTest\CallableParserFixture.cs" />
<Compile Include="EngineTest\NativeSQLQueryNonScalarReturnTest.cs" />
<Compile Include="EngineTest\NativeSQLQueryScalarReturnTest.cs" />
<Compile Include="EngineTest\NativeSQLQuerySpecificationTest.cs" />
Modified: trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/Mappings.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/Mappings.hbm.xml 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/Mappings.hbm.xml 2009-10-26 11:02:27 UTC (rev 4802)
@@ -39,7 +39,7 @@
</id>
<property name="name" not-null="true"/>
<loader query-ref="person"/>
- <sql-insert callable="true" check="none">call createPerson(?,?)</sql-insert>
+ <sql-insert callable="true" check="none">{ call createPerson(?, ?) }</sql-insert>
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update>
<sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
</class>
@@ -187,6 +187,23 @@
<database-object>
<create>
+ CREATE OR REPLACE PROCEDURE employmentsForRegion(rows OUT SYS_REFCURSOR, p_regionCode EMPLOYMENT.REGIONCODE%TYPE)
+ AS
+ BEGIN
+ OPEN rows FOR
+ SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE,
+ REGIONCODE, EMPID, VALUE, CURRENCY
+ FROM EMPLOYMENT
+ WHERE REGIONCODE = p_regionCode;
+ END;
+ </create>
+ <drop>
+ DROP PROCEDURE employmentsForRegion
+ </drop>
+ </database-object>
+
+ <database-object>
+ <create>
CREATE OR REPLACE PROCEDURE createPerson(p_name PERSON.NAME%TYPE, p_id PERSON.PERID%TYPE)
AS
rowcount INTEGER;
@@ -201,7 +218,7 @@
END;
</create>
<drop>
- DROP PROCEDURE createPerson;
+ DROP PROCEDURE createPerson
</drop>
</database-object>
Modified: trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/OracleCustomSQLFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/OracleCustomSQLFixture.cs 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/OracleCustomSQLFixture.cs 2009-10-26 11:02:27 UTC (rev 4802)
@@ -4,7 +4,7 @@
namespace NHibernate.Test.SqlTest.Custom.Oracle
{
- [TestFixture, Ignore("Not supported yet.")]
+ [TestFixture]
public class OracleCustomSQLFixture : CustomStoredProcSupportTest
{
protected override IList Mappings
@@ -12,9 +12,49 @@
get { return new[] { "SqlTest.Custom.Oracle.Mappings.hbm.xml", "SqlTest.Custom.Oracle.StoredProcedures.hbm.xml" }; }
}
+ protected override bool AppliesTo(NHibernate.Engine.ISessionFactoryImplementor factory)
+ {
+ return factory.ConnectionProvider.Driver is Driver.OracleDataClientDriver;
+ }
+
protected override bool AppliesTo(Dialect.Dialect dialect)
{
return dialect is Oracle8iDialect;
}
+
+ [Test]
+ public void RefCursorOutStoredProcedure()
+ {
+ ISession s = OpenSession();
+ ITransaction t = s.BeginTransaction();
+
+ Organization ifa = new Organization("IFA");
+ Organization jboss = new Organization("JBoss");
+ Person gavin = new Person("Gavin");
+ Person kevin = new Person("Kevin");
+ Employment emp = new Employment(gavin, jboss, "AU");
+ Employment emp2 = new Employment(kevin, ifa, "EU");
+ s.Save(ifa);
+ s.Save(jboss);
+ s.Save(gavin);
+ s.Save(kevin);
+ s.Save(emp);
+ s.Save(emp2);
+
+ IQuery namedQuery = s.GetNamedQuery("selectEmploymentsForRegion");
+ namedQuery.SetString("regionCode", "EU");
+ IList list = namedQuery.List();
+ Assert.That(list.Count, Is.EqualTo(1));
+ s.Delete(emp2);
+ s.Delete(emp);
+ s.Delete(ifa);
+ s.Delete(jboss);
+ s.Delete(kevin);
+ s.Delete(gavin);
+
+ t.Commit();
+ s.Close();
+ }
+
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/StoredProcedures.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/StoredProcedures.hbm.xml 2009-10-26 11:01:27 UTC (rev 4801)
+++ trunk/nhibernate/src/NHibernate.Test/SqlTest/Custom/Oracle/StoredProcedures.hbm.xml 2009-10-26 11:02:27 UTC (rev 4802)
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
This version is for Oracle drivers handling of stored procedures/functions.
-
-
- NOTE: so far this is the JAVA syntax, probably we will do something different in .NET
- or we can use the same syntax and solve the problem in each Oracle drive
-->
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
@@ -15,19 +11,19 @@
<sql-query name="simpleScalar" callable="true">
<return-scalar column="name" type="string"/>
<return-scalar column="value" type="long"/>
- call simpleScalar(:number)
+ { ? = call simpleScalar(:number) }
</sql-query>
<sql-query name="paramhandling" callable="true">
<return-scalar column="value" type="long"/>
<return-scalar column="value2" type="long"/>
- call testParamHandling(?,?)
+ { ? = call testParamHandling(?, ?) }
</sql-query>
<sql-query name="paramhandling_mixed" callable="true">
<return-scalar column="value" type="long"/>
<return-scalar column="value2" type="long"/>
- call testParamHandling(?,:second)
+ { ? = call testParamHandling(?,:second) }
</sql-query>
<sql-query name="selectAllEmployments" callable="true">
@@ -43,7 +39,23 @@
<return-column name="CURRENCY"/>
</return-property>
</return>
- call allEmployments()
+ { ? = call allEmployments }
</sql-query>
+ <sql-query name="selectEmploymentsForRegion" callable="true">
+ <return alias="emp" class="Employment">
+ <return-property name="employee" column="EMPLOYEE"/>
+ <return-property name="employer" column="EMPLOYER"/>
+ <return-property name="startDate" column="STARTDATE"/>
+ <return-property name="endDate" column="ENDDATE"/>
+ <return-property name="regionCode" column="REGIONCODE"/>
+ <return-property name="employmentId" column="EMPID"/>
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ </return>
+ { call employmentsForRegion(:regionCode) }
+ </sql-query>
+
</hibernate-mapping>
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|