From: <jul...@us...> - 2010-08-15 13:31:30
|
Revision: 5157 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5157&view=rev Author: julian-maughan Date: 2010-08-15 13:31:20 +0000 (Sun, 15 Aug 2010) Log Message: ----------- Changed dialect to preserve parameter indices in Order By statement (NH-2133, NH-1424) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs trunk/nhibernate/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2010-08-14 22:03:06 UTC (rev 5156) +++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2010-08-15 13:31:20 UTC (rev 5157) @@ -159,63 +159,65 @@ columnsOrAliases = new List<SqlString>(); aliasToColumn = new Dictionary<SqlString, SqlString>(); - IList<string> tokens = new QuotedAndParenthesisStringTokenizer(select.ToString()).GetTokens(); + IList<SqlString> tokens = new QuotedAndParenthesisStringTokenizer(select).GetTokens(); int index = 0; while (index < tokens.Count) { - string token = tokens[index]; - index += 1; + SqlString token = tokens[index]; + + int nextTokenIndex = index += 1; + + if (token.StartsWithCaseInsensitive("select")) + continue; - if ("select".Equals(token, StringComparison.InvariantCultureIgnoreCase)) - { + if (token.StartsWithCaseInsensitive("distinct")) continue; - } - if ("distinct".Equals(token, StringComparison.InvariantCultureIgnoreCase)) - { + + if (token.StartsWithCaseInsensitive(",")) continue; - } - if ("," == token) - { - continue; - } - if ("from".Equals(token, StringComparison.InvariantCultureIgnoreCase)) - { + if (token.StartsWithCaseInsensitive("from")) break; - } - //handle composite expressions like 2 * 4 as foo - while (index < tokens.Count && "as".Equals(tokens[index], StringComparison.InvariantCultureIgnoreCase) == false - && "," != tokens[index]) + // handle composite expressions like "2 * 4 as foo" + while ((nextTokenIndex < tokens.Count) && (tokens[nextTokenIndex].StartsWithCaseInsensitive("as") == false && tokens[nextTokenIndex].StartsWithCaseInsensitive(",") == false)) { - token = token + " " + tokens[index]; - index += 1; + SqlString nextToken = tokens[nextTokenIndex]; + token = token.Append(nextToken); + nextTokenIndex = index += 1; } - string alias = token; + // if there is no alias, the token and the alias will be the same + SqlString alias = token; - bool isFunctionCallOrQuotedString = token.Contains("'") || token.Contains("("); + bool isFunctionCallOrQuotedString = token.IndexOfCaseInsensitive("'") >= 0 || token.IndexOfCaseInsensitive("(") >= 0; + // this is heuristic guess, if the expression contains ' or (, it is probably // not appropriate to just slice parts off of it if (isFunctionCallOrQuotedString == false) { - int dot = token.IndexOf('.'); + // its a simple column reference, so lets set the alias to the + // column name minus the table qualifier if it exists + int dot = token.IndexOfCaseInsensitive("."); if (dot != -1) - { alias = token.Substring(dot + 1); - } } // notice! we are checking here the existence of "as" "alias", two // tokens from the current one - if (index + 1 < tokens.Count && "as".Equals(tokens[index], StringComparison.InvariantCultureIgnoreCase)) + if (nextTokenIndex + 1 < tokens.Count) { - alias = tokens[index + 1]; - index += 2; //skip the "as" and the alias \ + SqlString nextToken = tokens[nextTokenIndex]; + if (nextToken.IndexOfCaseInsensitive("as") >= 0) + { + SqlString tokenAfterNext = tokens[nextTokenIndex + 1]; + alias = tokenAfterNext; + index += 2; //skip the "as" and the alias + } } - columnsOrAliases.Add(new SqlString(alias)); - aliasToColumn[SqlString.Parse(alias)] = SqlString.Parse(token); + columnsOrAliases.Add(alias); + aliasToColumn[alias] = token; } } @@ -313,137 +315,144 @@ /// Notice that we aren't differenciating between [ ) and ( ] on purpose, it would complicate /// the code and it is not legal at any rate. /// </summary> - public class QuotedAndParenthesisStringTokenizer : IEnumerable<String> + public class QuotedAndParenthesisStringTokenizer : IEnumerable<SqlString> { - private readonly string original; + private readonly SqlString original; - public QuotedAndParenthesisStringTokenizer(string original) + public QuotedAndParenthesisStringTokenizer(SqlString original) { this.original = original; } - IEnumerator<string> IEnumerable<string>.GetEnumerator() + IEnumerator<SqlString> IEnumerable<SqlString>.GetEnumerator() { - StringBuilder currentToken = new StringBuilder(); TokenizerState state = TokenizerState.WhiteSpace; int parenthesisCount = 0; bool escapeQuote = false; - for (int i = 0; i < original.Length; i++) + int tokenStart = 0; + int tokenLength = 0; + string originalString = original.ToString(); + + for (int i = 0; i < originalString.Length; i++) { - char ch = original[i]; + char ch = originalString[i]; switch (state) { case TokenizerState.WhiteSpace: if (ch == '\'') { state = TokenizerState.Quoted; - currentToken.Append(ch); + tokenLength += 1; } else if (ch == ',') { - yield return ","; + yield return new SqlString(","); + //tokenLength += 1? } else if (ch == '(' || ch == '[') { state = TokenizerState.InParenthesis; - currentToken.Append(ch); + tokenLength += 1; parenthesisCount = 1; } else if (char.IsWhiteSpace(ch) == false) { state = TokenizerState.Token; - currentToken.Append(ch); + tokenLength += 1; } break; case TokenizerState.Quoted: if (escapeQuote) { escapeQuote = false; - currentToken.Append(ch); + tokenLength += 1; } // handle escaping of ' by using '' or \' - else if (ch == '\\' || (ch == '\'' && i + 1 < original.Length && original[i + 1] == '\'')) + else if (ch == '\\' || (ch == '\'' && i + 1 < originalString.Length && originalString[i + 1] == '\'')) { escapeQuote = true; - currentToken.Append(ch); + tokenLength += 1; } else if (ch == '\'') { - currentToken.Append(ch); - yield return currentToken.ToString(); + yield return original.Substring(tokenStart, tokenLength); + tokenStart += tokenLength + 1; + tokenLength = 0; state = TokenizerState.WhiteSpace; - currentToken.Length = 0; } else { - currentToken.Append(ch); + tokenLength += 1; } break; case TokenizerState.InParenthesis: if (ch == ')' || ch == ']') { - currentToken.Append(ch); + tokenLength += 1; parenthesisCount -= 1; if (parenthesisCount == 0) { - yield return currentToken.ToString(); - currentToken.Length = 0; + yield return original.Substring(tokenStart, tokenLength); + tokenStart += tokenLength + 1; + tokenLength = 0; state = TokenizerState.WhiteSpace; } } else if (ch == '(' || ch == '[') { - currentToken.Append(ch); + tokenLength += 1; parenthesisCount += 1; } else { - currentToken.Append(ch); + tokenLength += 1; } break; case TokenizerState.Token: if (char.IsWhiteSpace(ch)) { - yield return currentToken.ToString(); - currentToken.Length = 0; + yield return original.Substring(tokenStart, tokenLength); + tokenStart += tokenLength + 1; + tokenLength = 0; state = TokenizerState.WhiteSpace; } else if (ch == ',') // stop current token, and send the , as well { - yield return currentToken.ToString(); - currentToken.Length = 0; - yield return ","; + yield return original.Substring(tokenStart, tokenLength); + yield return new SqlString(","); + tokenStart += tokenLength + 2; + tokenLength = 0; state = TokenizerState.WhiteSpace; } else if (ch == '(' || ch == '[') { state = TokenizerState.InParenthesis; parenthesisCount = 1; - currentToken.Append(ch); + tokenLength += 1; } else if (ch == '\'') { state = TokenizerState.Quoted; - currentToken.Append(ch); + tokenLength += 1; } else { - currentToken.Append(ch); + tokenLength += 1; } break; default: throw new InvalidExpressionException("Could not understand the string " + original); } } - if (currentToken.Length > 0) + if (tokenLength > 0) { - yield return currentToken.ToString(); + yield return original.Substring(tokenStart, tokenLength); } } public IEnumerator GetEnumerator() { - return ((IEnumerable<string>)this).GetEnumerator(); + return ((IEnumerable<SqlString>)this).GetEnumerator(); } public enum TokenizerState @@ -454,9 +463,9 @@ Token } - public IList<string> GetTokens() + public IList<SqlString> GetTokens() { - return new List<string>(this); + return new List<SqlString>(this); } } } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs 2010-08-14 22:03:06 UTC (rev 5156) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs 2010-08-15 13:31:20 UTC (rev 5157) @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Generic; using NHibernate.Dialect; using NHibernate.Criterion; using NHibernate.SqlCommand; @@ -10,8 +11,6 @@ namespace NHibernate.Test.Criteria { - using System.Collections.Generic; - [TestFixture] public class CriteriaQueryTest : TestCase { @@ -127,32 +126,32 @@ } } - [Test] - public void TestSubcriteriaBeingNull() - { - ISession session = OpenSession(); - ITransaction t = session.BeginTransaction(); + [Test] + public void TestSubcriteriaBeingNull() + { + ISession session = OpenSession(); + ITransaction t = session.BeginTransaction(); - Course hibernateCourse = new Course(); - hibernateCourse.CourseCode = "HIB"; - hibernateCourse.Description = "Hibernate Training"; - session.Save(hibernateCourse); + Course hibernateCourse = new Course(); + hibernateCourse.CourseCode = "HIB"; + hibernateCourse.Description = "Hibernate Training"; + session.Save(hibernateCourse); - DetachedCriteria subcriteria = DetachedCriteria.For<Enrolment>("e"); - subcriteria.Add(Expression.EqProperty("e.CourseCode", "c.CourseCode")); - subcriteria.SetProjection(Projections.Avg("Semester")); + DetachedCriteria subcriteria = DetachedCriteria.For<Enrolment>("e"); + subcriteria.Add(Expression.EqProperty("e.CourseCode", "c.CourseCode")); + subcriteria.SetProjection(Projections.Avg("Semester")); - DetachedCriteria criteria = DetachedCriteria.For<Course>("c"); - criteria.SetProjection(Projections.Count("id")); - criteria.Add(Expression.Or(Subqueries.Le(5, subcriteria), Subqueries.IsNull(subcriteria))); + DetachedCriteria criteria = DetachedCriteria.For<Course>("c"); + criteria.SetProjection(Projections.Count("id")); + criteria.Add(Expression.Or(Subqueries.Le(5, subcriteria), Subqueries.IsNull(subcriteria))); - object o = criteria.GetExecutableCriteria(session).UniqueResult(); - Assert.AreEqual(1, o); + object o = criteria.GetExecutableCriteria(session).UniqueResult(); + Assert.AreEqual(1, o); - session.Delete(hibernateCourse); - t.Commit(); - session.Close(); - } + session.Delete(hibernateCourse); + t.Commit(); + session.Close(); + } [Test] public void Subselect() @@ -571,7 +570,6 @@ //it should not be already loaded Enrolment shouldNotBeLoaded = (Enrolment)s.Load(typeof(Enrolment), key); Assert.IsFalse(NHibernateUtil.IsInitialized(shouldNotBeLoaded)); - } using (ISession s = OpenSession()) @@ -1567,7 +1565,6 @@ } } - [Test] public void DetachedCriteriaInspection() { @@ -1645,15 +1642,16 @@ .SetMaxResults(3) .List(); - Assert.AreEqual(2, result.Count); - Assert.IsInstanceOfType(typeof(Student), result[0]); - Assert.IsInstanceOfType(typeof(Student), result[1]); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result[0], Is.InstanceOf(typeof(Student))); + Assert.That(result[1], Is.InstanceOf(typeof(Student))); session.Delete(gavin); session.Delete(bizarroGavin); t.Commit(); session.Close(); } + [Test] public void CacheDetachedCriteria() { @@ -1681,8 +1679,8 @@ Assert.That(sessions.Statistics.QueryCacheHitCount, Is.EqualTo(1)); sessions.Statistics.IsStatisticsEnabled = false; } - } + [Test] public void PropertyWithFormulaAndPagingTest() { @@ -1749,7 +1747,6 @@ } } - [Test] public void TransformToRowCountTest() { @@ -1776,19 +1773,68 @@ { ICriteria criteria = session.CreateCriteria(typeof(Student), "c"); - criteria - .AddOrder(Order.Asc( - Projections.Conditional( - Restrictions.Eq("StudentNumber", (long)1), - Projections.Constant(0), - Projections.Constant(1) - ))); + criteria.AddOrder( + Order.Asc( + Projections.Conditional( + Restrictions.Eq("StudentNumber", (long)1), + Projections.Constant(0), + Projections.Constant(1)))); criteria.List(); } } [Test] + public void OrderProjectionAliasedTest() + { + ISession session = OpenSession(); + ITransaction t = session.BeginTransaction(); + + Course courseA = new Course(); + courseA.CourseCode = "HIB-A"; + courseA.Description = "Hibernate Training A"; + session.Save(courseA); + + Student gavin = new Student(); + gavin.Name = "Gavin King"; + gavin.StudentNumber = 232; + gavin.PreferredCourse = courseA; + session.Save(gavin); + + Student leonardo = new Student(); + leonardo.Name = "Leonardo Quijano"; + leonardo.StudentNumber = 233; + leonardo.PreferredCourse = courseA; + session.Save(leonardo); + + Student johnDoe = new Student(); + johnDoe.Name = "John Doe"; + johnDoe.StudentNumber = 235; + johnDoe.PreferredCourse = null; + session.Save(johnDoe); + + IProjection conditional = + Projections.Conditional( + Restrictions.Eq("Name", "Gavin King"), + Projections.Constant("Name"), + Projections.Constant("AnotherName")); + + ICriteria criteria = session.CreateCriteria(typeof(Student)); + criteria.SetMaxResults(1); + criteria.SetFirstResult(1); + IList result = criteria.SetProjection(Projections.Alias(conditional, "CheckName")) + .AddOrder(Order.Asc("CheckName")) + .List(); + + session.Delete(gavin); + session.Delete(leonardo); + session.Delete(johnDoe); + session.Delete(courseA); + t.Commit(); + session.Close(); + } + + [Test] public void LikeProjectionTest() { Student john = new Student { Name = "John" }; @@ -1798,7 +1844,6 @@ session.Flush(); } - using (ISession session = this.OpenSession()) { ICriteria criteria = session.CreateCriteria(typeof(Student), "c"); @@ -1850,7 +1895,6 @@ } } - [Test] public void AliasJoinCriterion() { @@ -1956,4 +2000,4 @@ } } } -} +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs 2010-08-14 22:03:06 UTC (rev 5156) +++ trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs 2010-08-15 13:31:20 UTC (rev 5157) @@ -112,7 +112,7 @@ { MsSql2005Dialect.QuotedAndParenthesisStringTokenizer tokenizier = new MsSql2005Dialect.QuotedAndParenthesisStringTokenizer( - "select concat(a.Description,', ', a.Description) from Animal a"); + new SqlString("select concat(a.Description,', ', a.Description) from Animal a")); string[] expected = new string[] { "select", @@ -122,9 +122,9 @@ "a" }; int current = 0; - foreach (string token in tokenizier) + foreach (SqlString token in tokenizier) { - Assert.AreEqual(expected[current], token); + Assert.AreEqual(expected[current], token.ToString()); current += 1; } Assert.AreEqual(current, expected.Length); @@ -135,7 +135,7 @@ { MsSql2005Dialect.QuotedAndParenthesisStringTokenizer tokenizier = new MsSql2005Dialect.QuotedAndParenthesisStringTokenizer( - "SELECT fish.id, cast('astring, with,comma' as string) as bar, f FROM fish"); + new SqlString("SELECT fish.id, cast('astring, with,comma' as string) as bar, f FROM fish")); string[] expected = new string[] { "SELECT", @@ -150,10 +150,10 @@ "fish" }; int current = 0; - IList<string> tokens = tokenizier.GetTokens(); - foreach (string token in tokens) + IList<SqlString> tokens = tokenizier.GetTokens(); + foreach (SqlString token in tokens) { - Assert.AreEqual(expected[current], token); + Assert.AreEqual(expected[current], token.ToString()); current += 1; } Assert.AreEqual(current, expected.Length); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |