|
From: <fab...@us...> - 2009-05-05 18:07:11
|
Revision: 4246
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4246&view=rev
Author: fabiomaulo
Date: 2009-05-05 18:07:06 +0000 (Tue, 05 May 2009)
Log Message:
-----------
Continue port of AST tests for Updates
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/MultiTableUpdateExecutor.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs
trunk/nhibernate/src/NHibernate/NHibernate.csproj
trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BulkManipulation.cs
Added Paths:
-----------
trunk/nhibernate/src/NHibernate/Param/VersionTypeSeedParameterSpecification.cs
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/MultiTableUpdateExecutor.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/MultiTableUpdateExecutor.cs 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/MultiTableUpdateExecutor.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -22,7 +22,7 @@
private readonly SqlString[] updates;
private readonly IParameterSpecification[][] hqlParameters;
- public MultiTableUpdateExecutor(IStatement statement, ILog log) : base(statement, log)
+ public MultiTableUpdateExecutor(IStatement statement) : base(statement, log)
{
if (!Factory.Dialect.SupportsTemporaryTables)
{
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -11,6 +11,7 @@
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Type;
+using NHibernate.UserTypes;
using NHibernate.Util;
namespace NHibernate.Hql.Ast.ANTLR
@@ -167,12 +168,69 @@
void PrepareVersioned(IASTNode updateNode, IASTNode versioned)
{
- throw new NotImplementedException(); // DML
+ var updateStatement = (UpdateStatement)updateNode;
+ FromClause fromClause = updateStatement.FromClause;
+ if (versioned != null)
+ {
+ // Make sure that the persister is versioned
+ IQueryable persister = fromClause.GetFromElement().Queryable;
+ if (!persister.IsVersioned)
+ {
+ throw new SemanticException("increment option specified for update of non-versioned entity");
+ }
+
+ IVersionType versionType = persister.VersionType;
+ if (versionType is IUserVersionType)
+ {
+ throw new SemanticException("user-defined version types not supported for increment option");
+ }
+
+ IASTNode eq = ASTFactory.CreateNode(EQ, "=");
+ IASTNode versionPropertyNode = GenerateVersionPropertyNode(persister);
+
+ eq.SetFirstChild(versionPropertyNode);
+
+ IASTNode versionIncrementNode;
+ if (typeof(DateTime).IsAssignableFrom(versionType.ReturnedClass))
+ {
+ versionIncrementNode = ASTFactory.CreateNode(PARAM, "?");
+ IParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification(versionType);
+ ((ParameterNode)versionIncrementNode).HqlParameterSpecification = paramSpec;
+ Parameters.Insert(0, paramSpec);
+ }
+ else
+ {
+ // Not possible to simply re-use the versionPropertyNode here as it causes
+ // OOM errors due to circularity :(
+ versionIncrementNode = ASTFactory.CreateNode(PLUS, "+");
+ versionIncrementNode.SetFirstChild(GenerateVersionPropertyNode(persister));
+ versionIncrementNode.AddChild(ASTFactory.CreateNode(IDENT, "1"));
+ }
+
+ eq.AddChild(versionIncrementNode);
+
+ EvaluateAssignment(eq, persister, 0);
+
+ IASTNode setClause = updateStatement.SetClause;
+ IASTNode currentFirstSetElement = setClause.GetFirstChild();
+ setClause.SetFirstChild(eq);
+ eq.NextSibling= currentFirstSetElement;
+ }
}
+ private IASTNode GenerateVersionPropertyNode(IQueryable persister)
+ {
+ string versionPropertyName = persister.PropertyNames[persister.VersionProperty];
+ var versionPropertyRef = ASTFactory.CreateNode(IDENT, versionPropertyName);
+ var versionPropertyNode = LookupNonQualifiedProperty(versionPropertyRef);
+ Resolve(versionPropertyNode);
+ return versionPropertyNode;
+ }
+
void PostProcessUpdate(IASTNode update)
{
- throw new NotImplementedException(); // DML
+ var updateStatement = (UpdateStatement)update;
+ PostProcessDML(updateStatement);
}
void PostProcessDelete(IASTNode delete)
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -242,10 +242,12 @@
var list = new List<string>();
if (IsManipulationStatement)
{
- SqlString[] sqlStatements = statementExecutor.SqlStatements;
- foreach (var sqlStatement in sqlStatements)
+ foreach (var sqlStatement in statementExecutor.SqlStatements)
{
- list.Add(sqlStatement.ToString());
+ if (sqlStatement != null)
+ {
+ list.Add(sqlStatement.ToString());
+ }
}
}
else
@@ -419,7 +421,7 @@
// even here, if only properties mapped to the "base table" are referenced
// in the set and where clauses, this could be handled by the BasicDelegate.
// TODO : decide if it is better performance-wise to perform that check, or to simply use the MultiTableUpdateDelegate
- return new MultiTableDeleteExecutor(statement);
+ return new MultiTableUpdateExecutor(statement);
}
else
{
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -262,6 +262,24 @@
return null;
}
+ set
+ {
+ if (_parent != null)
+ {
+ if (_parent.ChildCount > (ChildIndex + 1))
+ {
+ _parent.SetChild(ChildIndex + 1, value);
+ }
+ else
+ {
+ AddSibling(value);
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("Trying set NextSibling without a parent.");
+ }
+ }
}
public IASTNode GetChild(int index)
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -15,7 +15,7 @@
int ChildCount { get; }
int ChildIndex { get; }
IASTNode Parent { get; set; }
- IASTNode NextSibling { get; }
+ IASTNode NextSibling { get; set; }
IASTNode GetChild(int index);
IASTNode GetFirstChild();
void SetFirstChild(IASTNode newChild);
Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-05-05 18:07:06 UTC (rev 4246)
@@ -589,6 +589,7 @@
<Compile Include="Hql\Ast\ANTLR\Util\JoinProcessor.cs" />
<Compile Include="Hql\Ast\ANTLR\Util\LiteralProcessor.cs" />
<Compile Include="Hql\Ast\ANTLR\Util\NodeTraverser.cs" />
+ <Compile Include="Param\VersionTypeSeedParameterSpecification.cs" />
<Compile Include="SqlCommand\InsertSelect.cs" />
<Compile Include="Util\NullableDictionary.cs" />
<Compile Include="Hql\Ast\ANTLR\Util\PathHelper.cs" />
Added: trunk/nhibernate/src/NHibernate/Param/VersionTypeSeedParameterSpecification.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Param/VersionTypeSeedParameterSpecification.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Param/VersionTypeSeedParameterSpecification.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -0,0 +1,36 @@
+using System.Data;
+using NHibernate.Engine;
+using NHibernate.Type;
+
+namespace NHibernate.Param
+{
+ public class VersionTypeSeedParameterSpecification : IParameterSpecification
+ {
+ private readonly IVersionType type;
+
+ public VersionTypeSeedParameterSpecification(IVersionType type)
+ {
+ this.type = type;
+ }
+
+ public int Bind(IDbCommand statement, QueryParameters qp, ISessionImplementor session, int position)
+ {
+ type.NullSafeSet(statement, type.Seed(session), position, session);
+ return 1;
+ }
+
+ public IType ExpectedType
+ {
+ get { return type; }
+ set
+ {
+ // expected type is intrinsic here...
+ }
+ }
+
+ public string RenderDisplayInfo()
+ {
+ return "version-seed, type=" + type;
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BulkManipulation.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BulkManipulation.cs 2009-05-05 15:38:45 UTC (rev 4245)
+++ trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BulkManipulation.cs 2009-05-05 18:07:06 UTC (rev 4246)
@@ -44,6 +44,81 @@
}
}
+ [Test]
+ public void UpdateWithWhereExistsSubquery()
+ {
+ // multi-table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ISession s = OpenSession();
+ ITransaction t = s.BeginTransaction();
+ var joe = new Human { Name = new Name { First = "Joe", Initial = 'Q', Last = "Public" } };
+ s.Save(joe);
+ var doll = new Human {Name = new Name {First = "Kyu", Initial = 'P', Last = "Doll"}, Friends = new[] {joe}};
+ s.Save(doll);
+ t.Commit();
+ s.Close();
+
+ s = OpenSession();
+ t = s.BeginTransaction();
+ string updateQryString = "update Human h " +
+ "set h.description = 'updated' " +
+ "where exists (" +
+ " select f.id " +
+ " from h.friends f " +
+ " where f.name.last = 'Public' " +
+ ")";
+ int count = s.CreateQuery(updateQryString).ExecuteUpdate();
+ Assert.That(count, Is.EqualTo(1));
+ s.Delete(doll);
+ s.Delete(joe);
+ t.Commit();
+ s.Close();
+
+ // single-table (one-to-many & many-to-many) ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ s = OpenSession();
+ t = s.BeginTransaction();
+ var entity = new SimpleEntityWithAssociation();
+ var other = new SimpleEntityWithAssociation();
+ entity.Name= "main";
+ other.Name= "many-to-many-association";
+ entity.ManyToManyAssociatedEntities.Add(other);
+ entity.AddAssociation("one-to-many-association");
+ s.Save(entity);
+ t.Commit();
+ s.Close();
+
+ s = OpenSession();
+ t = s.BeginTransaction();
+ // one-to-many test
+ updateQryString = "update SimpleEntityWithAssociation e " +
+ "set e.Name = 'updated' " +
+ "where exists (" +
+ " select a.id " +
+ " from e.AssociatedEntities a " +
+ " where a.Name = 'one-to-many-association' " +
+ ")";
+ count = s.CreateQuery(updateQryString).ExecuteUpdate();
+ Assert.That(count, Is.EqualTo(1));
+ // many-to-many test
+ if (Dialect.SupportsSubqueryOnMutatingTable)
+ {
+ updateQryString = "update SimpleEntityWithAssociation e " +
+ "set e.Name = 'updated' " +
+ "where exists (" +
+ " select a.id " +
+ " from e.ManyToManyAssociatedEntities a " +
+ " where a.Name = 'many-to-many-association' " +
+ ")";
+ count = s.CreateQuery(updateQryString).ExecuteUpdate();
+ Assert.That(count, Is.EqualTo(1));
+ }
+ var mtm = entity.ManyToManyAssociatedEntities.GetEnumerator();
+ mtm.MoveNext();
+ s.Delete(mtm.Current);
+ s.Delete(entity);
+ t.Commit();
+ s.Close();
+ }
+
#endregion
#region DELETES
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|