|
From: <fab...@us...> - 2009-05-02 05:10:05
|
Revision: 4223
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4223&view=rev
Author: fabiomaulo
Date: 2009-05-02 05:10:00 +0000 (Sat, 02 May 2009)
Log Message:
-----------
First test for executable HQL passed
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/BasicExecutor.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/FromClause.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/ASTIterator.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/CollectingNodeVisitor.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs
trunk/nhibernate/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs
trunk/nhibernate/src/NHibernate.Test/BulkManipulation/SimpleClass.hbm.xml
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/BasicExecutor.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/BasicExecutor.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Exec/BasicExecutor.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -6,9 +6,11 @@
using log4net;
using NHibernate.Engine;
using NHibernate.Exceptions;
+using NHibernate.Hql.Ast.ANTLR.Tree;
using NHibernate.Param;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
+using NHibernate.SqlTypes;
namespace NHibernate.Hql.Ast.ANTLR.Exec
{
@@ -17,18 +19,19 @@
{
private readonly IQueryable persister;
private static readonly ILog log = LogManager.GetLogger(typeof(QueryTranslatorImpl));
- private SqlString sql;
+ private readonly SqlString sql;
- public BasicExecutor(HqlSqlWalker walker, IQueryable persister) : base(walker, log)
+ public BasicExecutor(IStatement statement, ITokenStream tokenStream, IQueryable persister)
+ : base(statement.Walker, log)
{
this.persister = persister;
try
{
+ var generator = new HqlSqlGenerator(statement, tokenStream, Factory);
+ generator.Generate();
- //SqlGenerator gen = new SqlGenerator(Factory);
- //gen.statement(walker.getAST());
- //sql = gen.GetSQL();
- //gen.ParseErrorHandler.ThrowQueryException();
+ sql = generator.Sql;
+ Parameters = generator.CollectionParameters;
}
catch (RecognitionException e)
{
@@ -36,6 +39,8 @@
}
}
+ protected IList<IParameterSpecification> Parameters{get;private set;}
+
protected ISessionFactoryImplementor Factory
{
get
@@ -60,8 +65,13 @@
{
try
{
- //st = session.Batcher.PrepareCommand(CommandType.Text, sql, parameterTypes);
- IEnumerator<IParameterSpecification> paramSpecifications = Walker.Parameters.GetEnumerator();
+ var parameterTypes = new List<SqlType>(Parameters.Count);
+ foreach (var parameterSpecification in Parameters)
+ {
+ parameterTypes.AddRange(parameterSpecification.ExpectedType.SqlTypes(Factory));
+ }
+ st = session.Batcher.PrepareCommand(CommandType.Text, sql, parameterTypes.ToArray());
+ IEnumerator<IParameterSpecification> paramSpecifications = Parameters.GetEnumerator();
int pos = 1;
while (paramSpecifications.MoveNext())
{
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -165,7 +165,7 @@
void PostProcessDelete(IASTNode delete)
{
- throw new NotImplementedException(); // DML
+ PostProcessDML((DeleteStatement)delete);
}
void PostProcessInsert(IASTNode insert)
@@ -173,6 +173,24 @@
throw new NotImplementedException(); // DML
}
+ private void PostProcessDML(IRestrictableStatement statement)
+ {
+ statement.FromClause.Resolve();
+
+ var fromElement = (FromElement)statement.FromClause.GetFromElements()[0];
+ IQueryable persister = fromElement.Queryable;
+ // Make #@%$^#^&# sure no alias is applied to the table name
+ fromElement.Text = persister.TableName;
+
+ // append any filter fragments; the EMPTY_MAP is used under the assumption that
+ // currently enabled filters should not affect this process
+ if (persister.DiscriminatorType != null)
+ {
+ new SyntheticAndFactory(this)
+ .AddDiscriminatorWhereFragment(statement, persister, new CollectionHelper.EmptyMapClass<string, IFilter>(), fromElement.TableAlias);
+ }
+ }
+
void AfterStatementCompletion(string statementName)
{
if (log.IsDebugEnabled)
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -166,9 +166,18 @@
public int ExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session)
{
- throw new System.NotImplementedException(); // DML
+ ErrorIfSelect();
+ return statementExecutor.Execute(queryParameters, session);
}
+ private void ErrorIfSelect()
+ {
+ if (!sqlAst.NeedsExecutor)
+ {
+ throw new QueryExecutionRequestException("Not supported for select queries:", _hql);
+ }
+ }
+
public NHibernate.Loader.Loader Loader
{
get { return _queryLoader; }
@@ -229,17 +238,14 @@
{
get
{
- List<string> list = new List<string>();
+ var list = new List<string>();
if (IsManipulationStatement)
{
- throw new NotImplementedException(); // DML
- /*
- String[] sqlStatements = statementExecutor.getSqlStatements();
- for (int i = 0; i < sqlStatements.length; i++)
+ SqlString[] sqlStatements = statementExecutor.SqlStatements;
+ foreach (var sqlStatement in sqlStatements)
{
- list.Add(sqlStatements[i]);
+ list.Add(sqlStatement.ToString());
}
- */
}
else
{
@@ -340,7 +346,7 @@
// PHASE 2 : Analyze the HQL AST, and produce an SQL AST.
HqlSqlWalker w = Analyze(parser, collectionRole);
- sqlAst = (IStatement)w.statement().Tree;
+ sqlAst = _translator.SqlStatement;
// at some point the generate phase needs to be moved out of here,
// because a single object-level DML might spawn multiple SQL DML
@@ -353,14 +359,14 @@
// QueryLoader currently even has a dependency on this at all; does
// it need it? Ideally like to see the walker itself given to the delegates directly...
- if (_translator.SqlStatement.NeedsExecutor)
+ if (sqlAst.NeedsExecutor)
{
- statementExecutor = BuildAppropriateStatementExecutor(w);
+ statementExecutor = BuildAppropriateStatementExecutor(sqlAst);
}
else
{
// PHASE 3 : Generate the SQL.
- _generator = new HqlSqlGenerator(_translator.SqlStatement, parser.Tokens, _factory);
+ _generator = new HqlSqlGenerator(sqlAst, parser.Tokens, _factory);
_generator.Generate();
_queryLoader = new QueryLoader(this, _factory, w.SelectClause);
@@ -387,8 +393,9 @@
_enabledFilters = null; //only needed during compilation phase...
}
- private IStatementExecutor BuildAppropriateStatementExecutor(HqlSqlWalker walker)
+ private IStatementExecutor BuildAppropriateStatementExecutor(IStatement statement)
{
+ HqlSqlWalker walker = statement.Walker;
if (walker.StatementType == HqlSqlWalker.DELETE)
{
FromElement fromElement = walker.GetFinalFromClause().GetFromElement();
@@ -400,7 +407,7 @@
}
else
{
- return new BasicExecutor(walker, persister);
+ return new BasicExecutor(statement, _parser.Tokens, persister);
}
}
else if (walker.StatementType == HqlSqlWalker.UPDATE)
@@ -417,7 +424,7 @@
}
else
{
- return new BasicExecutor(walker, persister);
+ return new BasicExecutor(statement, _parser.Tokens, persister);
}
}
else if (walker.StatementType == HqlSqlWalker.INSERT)
@@ -645,12 +652,12 @@
private static readonly ILog log = LogManager.GetLogger(typeof(HqlSqlGenerator));
private readonly IASTNode _ast;
- private readonly CommonTokenStream _tokens;
+ private readonly ITokenStream _tokens;
private readonly ISessionFactoryImplementor _sfi;
private SqlString _sql;
private IList<IParameterSpecification> _parameters;
- public HqlSqlGenerator(IStatement ast, CommonTokenStream tokens, ISessionFactoryImplementor sfi)
+ public HqlSqlGenerator(IStatement ast, ITokenStream tokens, ISessionFactoryImplementor sfi)
{
_ast = (IASTNode) ast;
_tokens = tokens;
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -273,7 +273,17 @@
return _children[index];
}
- public void SetChild(int index, IASTNode newChild)
+ public IASTNode GetFirstChild()
+ {
+ return GetChild(0);
+ }
+
+ public void SetFirstChild(IASTNode newChild)
+ {
+ SetChild(0, newChild);
+ }
+
+ public void SetChild(int index, IASTNode newChild)
{
if ((_children == null) || _children.Count <= index)
{
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -360,5 +360,23 @@
{
return "FromClause{" + "level=" + _level + "}";
}
+
+ public virtual void Resolve()
+ {
+ // Make sure that all from elements registered with this FROM clause are actually in the AST.
+ var iter = (new ASTIterator(GetFirstChild())).GetEnumerator();
+ var childrenInTree = new HashedSet<IASTNode>();
+ while (iter.MoveNext())
+ {
+ childrenInTree.Add(iter.Current);
+ }
+ foreach (var fromElement in _fromElements)
+ {
+ if (!childrenInTree.Contains(fromElement))
+ {
+ throw new SemanticException("Element not in AST: " + fromElement);
+ }
+ }
+ }
}
}
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -33,8 +33,7 @@
ret = new SqlNode(payload);
break;
case HqlSqlWalker.DELETE:
- //return DeleteStatement.class;
- ret = new SqlNode(payload);
+ ret = new DeleteStatement(payload);
break;
case HqlSqlWalker.INSERT:
//return InsertStatement.class;
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/IASTNode.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -17,7 +17,9 @@
IASTNode Parent { get; set; }
IASTNode NextSibling { get; }
IASTNode GetChild(int index);
- void SetChild(int index, IASTNode newChild);
+ IASTNode GetFirstChild();
+ void SetFirstChild(IASTNode newChild);
+ void SetChild(int index, IASTNode newChild);
IASTNode AddChild(IASTNode childNode);
IASTNode InsertChild(int index, IASTNode child);
IASTNode AddSibling(IASTNode newSibling);
@@ -30,7 +32,7 @@
// TODO - not sure we need this...
IToken Token { get; }
-
+
string ToStringTree();
}
}
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/ASTIterator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/ASTIterator.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/ASTIterator.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -13,14 +13,16 @@
[CLSCompliant(false)]
public class ASTIterator : IEnumerable<IASTNode>
{
+ private readonly Stack<IASTNode> _stack = new Stack<IASTNode>();
private IASTNode _current;
- private readonly Stack<IASTNode> _stack = new Stack<IASTNode>();
public ASTIterator(IASTNode tree)
{
_current = tree;
}
+ #region IEnumerable<IASTNode> Members
+
public IEnumerator<IASTNode> GetEnumerator()
{
Down();
@@ -45,17 +47,20 @@
}
}
- private void Down() {
- while ( _current != null && _current.ChildCount > 0)
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ #endregion
+
+ private void Down()
+ {
+ while (_current != null && _current.ChildCount > 0)
{
_stack.Push(_current);
_current = _current.GetChild(0);
}
}
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
}
-}
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/CollectingNodeVisitor.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/CollectingNodeVisitor.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/CollectingNodeVisitor.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -4,6 +4,11 @@
namespace NHibernate.Hql.Ast.ANTLR.Util
{
+ /// <summary>
+ /// Filters nodes in/out of a tree.
+ /// </summary>
+ /// <param name="node">The node to check.</param>
+ /// <returns>true to keep the node, false if the node should be filtered out.</returns>
[CLSCompliant(false)]
public delegate bool FilterPredicate(IASTNode node);
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -1,11 +1,12 @@
using System;
-using Antlr.Runtime.Tree;
using log4net;
using NHibernate.Hql.Ast.ANTLR.Tree;
using NHibernate.Param;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;
+using NHibernate.Persister.Entity;
+using System.Collections.Generic;
namespace NHibernate.Hql.Ast.ANTLR.Util
{
@@ -143,5 +144,45 @@
{
return _hqlSqlWalker.ASTFactory.CreateNode(tokenType, text);
}
+
+ public virtual void AddDiscriminatorWhereFragment(IRestrictableStatement statement, IQueryable persister, IDictionary<string, IFilter> enabledFilters, string alias)
+ {
+ string whereFragment = persister.FilterFragment(alias, enabledFilters).Trim();
+ if (string.Empty.Equals(whereFragment))
+ {
+ return;
+ }
+ if (whereFragment.StartsWith("and"))
+ {
+ whereFragment = whereFragment.Substring(4);
+ }
+
+ // Need to parse off the column qualifiers; this is assuming (which is true as of now)
+ // that this is only used from update and delete HQL statement parsing
+ whereFragment = StringHelper.Replace(whereFragment, persister.GenerateFilterConditionAlias(alias) + ".", "");
+
+ // Note: this simply constructs a "raw" SQL_TOKEN representing the
+ // where fragment and injects this into the tree. This "works";
+ // however it is probably not the best long-term solution.
+ //
+ // At some point we probably want to apply an additional grammar to
+ // properly tokenize this where fragment into constituent parts
+ // focused on the operators embedded within the fragment.
+ IASTNode discrimNode = Create(HqlSqlWalker.SQL_TOKEN, whereFragment);
+
+ if (statement.WhereClause.ChildCount == 0)
+ {
+ statement.WhereClause.SetFirstChild(discrimNode);
+ }
+ else
+ {
+ IASTNode and = Create(HqlSqlWalker.AND, "{and}");
+ IASTNode currentFirstChild = statement.WhereClause.GetFirstChild();
+ and.SetFirstChild(discrimNode);
+ and.AddChild(currentFirstChild);
+ statement.WhereClause.SetFirstChild(and);
+ }
+ }
+
}
}
Modified: trunk/nhibernate/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs 2009-05-02 05:10:00 UTC (rev 4223)
@@ -6,7 +6,7 @@
[TestFixture]
public class HqlBulkOperations: BaseFixture
{
- [Test, Ignore("Not supported yet.")]
+ [Test]
public void SimpleDelete()
{
using (var s = OpenSession())
Modified: trunk/nhibernate/src/NHibernate.Test/BulkManipulation/SimpleClass.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/BulkManipulation/SimpleClass.hbm.xml 2009-05-01 14:55:28 UTC (rev 4222)
+++ trunk/nhibernate/src/NHibernate.Test/BulkManipulation/SimpleClass.hbm.xml 2009-05-02 05:10:00 UTC (rev 4223)
@@ -3,7 +3,7 @@
assembly="NHibernate.Test"
namespace="NHibernate.Test.BulkManipulation">
- <class name="SimpleClass">
+ <class name="SimpleClass" table="TSIMPLE">
<id type="int">
<generator class="native" />
</id>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|