From: <fab...@us...> - 2008-08-13 14:59:15
|
Revision: 3701 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3701&view=rev Author: fabiomaulo Date: 2008-08-13 14:59:18 +0000 (Wed, 13 Aug 2008) Log Message: ----------- Support of parametrs in HQLFunctions (by Ricardo Stuven) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -78,7 +78,7 @@ { tokens.Add(replacemenToken); } - string functionStatement = sqlFunction.Render(tokens, criteriaQuery.Factory); + string functionStatement = sqlFunction.Render(tokens, criteriaQuery.Factory).ToString(); string[] splitted = functionStatement.Split(new string[] {replacemenToken}, StringSplitOptions.RemoveEmptyEntries); SqlStringBuilder sb = new SqlStringBuilder(); @@ -138,4 +138,4 @@ return types.ToArray(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -221,10 +221,15 @@ { } - public override string Render(IList args, ISessionFactoryImplementor factory) + public override SqlString Render(IList args, ISessionFactoryImplementor factory) { - base.Render(args, factory); - return string.Format("cast('{0}' as {1})", Name, FunctionReturnType.SqlTypes(factory)[0]); + return new SqlStringBuilder() + .Add("cast('") + .Add(name) + .Add("' as ") + .Add(returnType.SqlTypes(factory)[0].ToString()) + .Add(")") + .ToSqlString(); } } @@ -234,9 +239,9 @@ : base("current_timestamp", NHibernateUtil.DateTime, true) { } - public override string Render(IList args, ISessionFactoryImplementor factory) + public override SqlString Render(IList args, ISessionFactoryImplementor factory) { - return Name; + return new SqlString(name); } } @@ -245,4 +250,4 @@ return new FirebirdDataBaseSchema(connection); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -39,26 +40,26 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count < 2 || args.Count > 3) { throw new QueryException("substring(): Incorrect number of parameters (expected 2 or 3, got " + args.Count + ")"); } - StringBuilder cmd = new StringBuilder(); - cmd.Append("substring(") - .Append(args[0]) - .Append(" from ") - .Append(args[1]); + SqlStringBuilder cmd = new SqlStringBuilder(); + cmd.Add("substring(") + .AddObject(args[0]) + .Add(" from ") + .AddObject(args[1]); if (args.Count > 2) { - cmd.Append(" for ") - .Append(args[2]); + cmd.Add(" for ") + .AddObject(args[2]); } - cmd.Append(')'); - return cmd.ToString(); + cmd.Add(")"); + return cmd.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; using System.Text.RegularExpressions; @@ -79,14 +80,14 @@ /// If only trim specification is omitted, BOTH is assumed; /// if trim character is omitted, space is assumed /// </remarks> - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count < 1 || args.Count > 4) { throw new QueryException("function takes between 1 and 4 arguments"); } - string firstArg = (string) args[0]; + string firstArg = args[0].ToString(); if (args.Count == 1) { @@ -108,7 +109,7 @@ bool leading = true; // should leading trim-characters be trimmed? bool trailing = true; // should trailing trim-characters be trimmed? string trimCharacter = null; // the trim-character - string trimSource = null; // the trim-source + object trimSource = null; // the trim-source // potentialTrimCharacterArgIndex = 1 assumes that a // trim-specification has been specified. we handle the @@ -130,11 +131,11 @@ potentialTrimCharacterArgIndex = 0; } - string potentialTrimCharacter = (string) args[potentialTrimCharacterArgIndex]; - if (StringHelper.EqualsCaseInsensitive("from", potentialTrimCharacter)) + object potentialTrimCharacter = args[potentialTrimCharacterArgIndex]; + if (StringHelper.EqualsCaseInsensitive("from", potentialTrimCharacter.ToString())) { trimCharacter = "' '"; - trimSource = (string) args[potentialTrimCharacterArgIndex + 1]; + trimSource = args[potentialTrimCharacterArgIndex + 1]; } else if (potentialTrimCharacterArgIndex + 1 >= args.Count) { @@ -143,14 +144,14 @@ } else { - trimCharacter = potentialTrimCharacter; - if (StringHelper.EqualsCaseInsensitive("from", (string) args[potentialTrimCharacterArgIndex + 1])) + trimCharacter = potentialTrimCharacter.ToString(); + if (StringHelper.EqualsCaseInsensitive("from", args[potentialTrimCharacterArgIndex + 1].ToString())) { - trimSource = (string) args[potentialTrimCharacterArgIndex + 2]; + trimSource = args[potentialTrimCharacterArgIndex + 2]; } else { - trimSource = (string) args[potentialTrimCharacterArgIndex + 1]; + trimSource = args[potentialTrimCharacterArgIndex + 1]; } } @@ -208,4 +209,4 @@ #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.SqlTypes; using NHibernate.Type; @@ -34,13 +35,13 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count != 2) { throw new QueryException("cast() requires two arguments"); } - string typeName = (string) args[1]; + string typeName = args[1].ToString(); string sqlType = string.Empty; IType hqlType = TypeFactory.HeuristicType(typeName); if (hqlType != null) @@ -70,7 +71,13 @@ { throw new QueryException(string.Format("invalid Hibernate type for cast(): type {0} not found", typeName)); } - return String.Format("cast({0} as {1})", args[0], sqlType); + return new SqlStringBuilder() + .Add("cast(") + .AddObject(args[0]) + .Add(" as ") + .Add(sqlType) + .Add(")") + .ToSqlString(); } #endregion @@ -89,4 +96,4 @@ #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -32,7 +33,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { // TODO: QueryException if args.Count<2 (not present in H3.2) bool threeArgs = args.Count > 2; @@ -40,27 +41,27 @@ object orgString = args[1]; object start = threeArgs ? args[2] : null; - StringBuilder buf = new StringBuilder(); - buf.Append("charindex(") - .Append(pattern) - .Append(", "); + SqlStringBuilder buf = new SqlStringBuilder(); + buf.Add("charindex(") + .AddObject(pattern) + .Add(", "); if (threeArgs) { - buf.Append("right("); + buf.Add("right("); } - buf.Append(orgString); + buf.AddObject(orgString); if (threeArgs) { - buf.Append(", char_length(") - .Append(orgString) - .Append(")-(") - .Append(start) - .Append("-1))"); + buf.Add(", char_length(") + .AddObject(orgString) + .Add(")-(") + .AddObject(start) + .Add("-1))"); } - buf.Append(')'); - return buf.ToString(); + buf.Add(")"); + return buf.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; @@ -53,7 +54,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { //ANSI-SQL92 definition //<general set function> ::= @@ -69,22 +70,22 @@ { throw new QueryException(string.Format("Aggregate {0}(): invalid argument '*'.", name)); } - StringBuilder cmd = new StringBuilder(); - cmd.Append(name) - .Append("("); + SqlStringBuilder cmd = new SqlStringBuilder(); + cmd.Add(name) + .Add("("); if (args.Count > 1) { - string firstArg = args[0].ToString(); - if (!StringHelper.EqualsCaseInsensitive("distinct", firstArg) && - !StringHelper.EqualsCaseInsensitive("all", firstArg)) + object firstArg = args[0]; + if (!StringHelper.EqualsCaseInsensitive("distinct", firstArg.ToString()) && + !StringHelper.EqualsCaseInsensitive("all", firstArg.ToString())) { throw new QueryException(string.Format("Aggregate {0}(): token unknow {1}.", name, firstArg)); } - cmd.Append(firstArg).Append(' '); + cmd.AddObject(firstArg).Add(" "); } - cmd.Append(args[args.Count - 1]) - .Append(')'); - return cmd.ToString(); + cmd.AddObject(args[args.Count - 1]) + .Add(")"); + return cmd.ToSqlString(); } #endregion Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,5 +1,6 @@ using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -38,6 +39,6 @@ /// <param name="args">List of arguments</param> /// <param name="factory"></param> /// <returns>SQL fragment for the fuction.</returns> - string Render(IList args, ISessionFactoryImplementor factory); + SqlString Render(IList args, ISessionFactoryImplementor factory); } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,5 +1,6 @@ using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -9,8 +10,8 @@ /// </summary> public class NoArgSQLFunction : ISQLFunction { - private readonly IType returnType = null; - private readonly string name; + protected readonly IType returnType = null; + protected readonly string name; private readonly bool hasParenthesesIfNoArguments; public NoArgSQLFunction(string name, IType returnType) : this(name, returnType, true) @@ -51,15 +52,21 @@ get { return hasParenthesesIfNoArguments; } } - public virtual string Render(IList args, ISessionFactoryImplementor factory) + public virtual SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count > 0) { throw new QueryException("function takes no arguments: " + name); } - return hasParenthesesIfNoArguments ? name + "()" : name; + SqlStringBuilder buf = new SqlStringBuilder(2); + buf.Add(name); + if (hasParenthesesIfNoArguments) + { + buf.Add("()"); + } + return buf.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -31,7 +32,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { // DONE: QueryException if args.Count==0 (not present in H3.2) if (args.Count == 0) @@ -43,14 +44,19 @@ args.RemoveAt(lastIndex); if (lastIndex == 0) { - return last.ToString(); + return new SqlString(last); } object secondLast = args[lastIndex - 1]; - string nvl = "nvl(" + secondLast + ", " + last + ")"; - args[lastIndex - 1] = nvl; + SqlStringBuilder nvl = new SqlStringBuilder(5) + .Add("nvl(") + .AddObject(secondLast) + .Add(", ") + .AddObject(last) + .Add(")"); + args[lastIndex - 1] = nvl.ToSqlString(); return Render(args, factory); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -32,7 +33,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { // DONE: QueryException if args.Count<2 (not present in H3.2) if (args.Count < 2) @@ -44,35 +45,35 @@ object orgString = args[1]; object start = threeArgs ? args[2] : null; - StringBuilder buf = new StringBuilder(); + SqlStringBuilder buf = new SqlStringBuilder(); if (threeArgs) { - buf.Append('('); + buf.Add("("); } - buf.Append("position(") - .Append(pattern) - .Append(" in "); + buf.Add("position(") + .AddObject(pattern) + .Add(" in "); if (threeArgs) { - buf.Append("substring("); + buf.Add("substring("); } - buf.Append(orgString); + buf.AddObject(orgString); if (threeArgs) { - buf.Append(", ") - .Append(start) - .Append(')'); + buf.Add(", ") + .AddObject(start) + .Add(")"); } - buf.Append(')'); + buf.Add(")"); if (threeArgs) { - buf.Append('+') - .Append(start) - .Append("-1)"); + buf.Add("+") + .AddObject(start) + .Add("-1)"); } - return buf.ToString(); + return buf.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -3,6 +3,7 @@ using System.Text; using System.Text.RegularExpressions; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -98,9 +99,9 @@ /// <param name="args">args function arguments</param> /// <param name="factory">generated SQL function call</param> /// <returns></returns> - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { - StringBuilder buf = new StringBuilder(); + SqlStringBuilder buf = new SqlStringBuilder(); foreach (TemplateChunk tc in chunks) { if (tc.ArgumentIndex != InvalidArgumentIndex) @@ -110,15 +111,22 @@ // TODO: if (arg == null) QueryException is better ? if (arg != null) { - buf.Append(arg); + if (arg is Parameter || arg is SqlString) + { + buf.AddObject(arg); + } + else + { + buf.Add(arg.ToString()); + } } } else { - buf.Append(tc.Text); + buf.Add(tc.Text); } } - return buf.ToString(); + return buf.ToSqlString(); } #endregion @@ -128,4 +136,4 @@ return template; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -55,17 +56,25 @@ get { return true; } } - public virtual string Render(IList args, ISessionFactoryImplementor factory) + public virtual SqlString Render(IList args, ISessionFactoryImplementor factory) { - StringBuilder buf = new StringBuilder(); - buf.Append(name) - .Append('('); + SqlStringBuilder buf = new SqlStringBuilder(); + buf.Add(name) + .Add("("); for (int i = 0; i < args.Count; i++) { - buf.Append(args[i]); - if (i < (args.Count - 1)) buf.Append(", "); + object arg = args[i]; + if (arg is Parameter || arg is SqlString) + { + buf.AddObject(arg); + } + else + { + buf.Add(arg.ToString()); + } + if (i < (args.Count - 1)) buf.Add(", "); } - return buf.Append(')').ToString(); + return buf.Add(")").ToSqlString(); } #endregion @@ -75,4 +84,4 @@ return name; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -39,7 +40,7 @@ this.allowedArgsCount = allowedArgsCount; } - public override string Render(System.Collections.IList args, NHibernate.Engine.ISessionFactoryImplementor factory) + public override SqlString Render(System.Collections.IList args, NHibernate.Engine.ISessionFactoryImplementor factory) { if (args.Count!= allowedArgsCount) { Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -47,17 +48,17 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { - StringBuilder buf = new StringBuilder().Append(begin); + SqlStringBuilder buf = new SqlStringBuilder().Add(begin); for (int i = 0; i < args.Count; i++) { - buf.Append(args[i]); - if (i < args.Count - 1) buf.Append(sep); + buf.AddObject(args[i]); + if (i < args.Count - 1) buf.Add(sep); } - return buf.Append(end).ToString(); + return buf.Add(end).ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -30,6 +30,11 @@ result.Append(text); } + void ISqlStringVisitor.String(SqlString sqlString) + { + result.Append(sqlString.ToString()); + } + void ISqlStringVisitor.Parameter() { string name = formatter.GetParameterName(parameterIndex); @@ -37,4 +42,4 @@ result.Append(name); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -27,6 +27,11 @@ q.AppendGroupByToken(pathExpressionParser.WhereColumn); pathExpressionParser.AddAssociation(q); } + else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) + { + q.AddNamedParameter(token.Substring(1)); + q.AppendGroupByParameter(); + } else { q.AppendGroupByToken(token); @@ -46,4 +51,4 @@ pathExpressionParser.UseThetaStyleJoin = true; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -45,7 +45,7 @@ private readonly IDictionary<string, IAssociationType> uniqueKeyOwnerReferences = new Dictionary<string, IAssociationType>(); private readonly IDictionary<string, IPropertyMapping> decoratedPropertyMappings = new Dictionary<string, IPropertyMapping>(); - private readonly IList scalarSelectTokens = new ArrayList(); // contains a List of strings + private readonly IList<SqlString> scalarSelectTokens = new List<SqlString>(); private readonly IList<SqlString> whereTokens = new List<SqlString>(); private readonly IList<SqlString> havingTokens = new List<SqlString>(); private readonly IDictionary<string, JoinSequence> joins = new LinkedHashMap<string, JoinSequence>(); @@ -174,7 +174,9 @@ for (int i = 0; i < count; i++) { - sql.AddSelectFragmentString(((IQueryableCollection) persisters[i]).SelectFragment(names[i], suffixes[i])); + sql.AddSelectFragmentString(new SqlString( + ((IQueryableCollection) persisters[i]).SelectFragment( + (string) names[i], (string) suffixes[i]))); } } @@ -632,16 +634,26 @@ groupByTokens.Add(new SqlString(token)); } + internal void AppendGroupByParameter() + { + groupByTokens.Add(SqlString.Parameter); + } + internal void AppendScalarSelectToken(string token) { - scalarSelectTokens.Add(token); + scalarSelectTokens.Add(new SqlString(token)); } internal void AppendScalarSelectTokens(string[] tokens) { - scalarSelectTokens.Add(tokens); + scalarSelectTokens.Add(new SqlString(tokens)); } + internal void AppendScalarSelectParameter() + { + scalarSelectTokens.Add(SqlString.Parameter); + } + internal void AddJoin(string name, JoinSequence joinSequence) { if (!joins.ContainsKey(name)) @@ -747,7 +759,7 @@ owners = null; } - string scalarSelect = RenderScalarSelect(); //Must be done here because of side-effect! yuck... + SqlString scalarSelect = RenderScalarSelect(); //Must be done here because of side-effect! yuck... int scalarSize = scalarTypes.Count; hasScalars = scalarTypes.Count != rtsize; @@ -846,7 +858,7 @@ { string name = returnedTypes[k]; string suffix = size == 1 ? String.Empty : k.ToString() + StringHelper.Underscore; - sql.AddSelectFragmentString(persisters[k].IdentifierSelectFragment(name, suffix)); + sql.AddSelectFragmentString(new SqlString(persisters[k].IdentifierSelectFragment(name, suffix))); } } @@ -856,19 +868,19 @@ for (int k = 0; k < size; k++) { string suffix = (size == 1) ? String.Empty : k.ToString() + StringHelper.Underscore; - string name = returnedTypes[k]; - sql.AddSelectFragmentString(persisters[k].PropertySelectFragment(name, suffix, false)); + string name = (string) returnedTypes[k]; + sql.AddSelectFragmentString(new SqlString(persisters[k].PropertySelectFragment(name, suffix, false))); } } /// <summary> /// WARNING: side-effecty /// </summary> - private string RenderScalarSelect() + private SqlString RenderScalarSelect() { bool isSubselect = superQuery != null; - StringBuilder buf = new StringBuilder(20); + SqlStringBuilder buf = new SqlStringBuilder(); if (scalarTypes.Count == 0) { @@ -881,14 +893,14 @@ string[] _names = persisters[k].IdentifierColumnNames; for (int i = 0; i < _names.Length; i++) { - buf.Append(returnedTypes[k]).Append(StringHelper.Dot).Append(_names[i]); + buf.Add(returnedTypes[k].ToString()).Add(StringHelper.Dot.ToString()).Add(_names[i]); if (!isSubselect) { - buf.Append(" as ").Append(ScalarName(k, i)); + buf.Add(" as ").Add(ScalarName(k, i)); } if (i != _names.Length - 1 || k != size - 1) { - buf.Append(StringHelper.CommaSpace); + buf.Add(StringHelper.CommaSpace); } } } @@ -901,17 +913,17 @@ int parenCount = 0; // used to count the nesting of parentheses for (int tokenIdx = 0; tokenIdx < scalarSelectTokens.Count; tokenIdx++) { - object next = scalarSelectTokens[tokenIdx]; - if (next is string) + SqlString next = scalarSelectTokens[tokenIdx]; + if (next.Count == 1) { - string token = (string)next; + string token = next.ToString(); string lc = token.ToLowerInvariant(); ISQLFunction func = Factory.SQLFunctionRegistry.FindSQLFunction(lc); if (func != null) { // Render the HQL function - string renderedFunction = RenderFunctionClause(func, scalarSelectTokens, ref tokenIdx); - buf.Append(renderedFunction); + SqlString renderedFunction = RenderFunctionClause(func, scalarSelectTokens, ref tokenIdx); + buf.Add(renderedFunction); } else { @@ -933,47 +945,47 @@ { if (!isSubselect && parenCount == 0) { - buf.Append(" as ").Append(ScalarName(c++, 0)); + buf.Add(" as ").Add(ScalarName(c++, 0)); } } } - buf.Append(token); + buf.Add(token); if (lc.Equals("distinct") || lc.Equals("all")) { - buf.Append(' '); + buf.Add(" "); } } } else { nolast = true; - string[] tokens = (string[])next; - for (int i = 0; i < tokens.Length; i++) + int i = 0; + foreach (object token in next.Parts) { - buf.Append(tokens[i]); + buf.AddObject(token); if (!isSubselect) { - buf.Append(" as ").Append(ScalarName(c, i)); + buf.Add(" as ").Add(ScalarName(c, i)); } - if (i != tokens.Length - 1) + if (i != next.Count - 1) { - buf.Append(StringHelper.CommaSpace); + buf.Add(StringHelper.CommaSpace); } + i++; } c++; } } if (!isSubselect && !nolast) { - buf.Append(" as ").Append(ScalarName(c, 0)); + buf.Add(" as ").Add(ScalarName(c++, 0)); } } - return buf.ToString(); + return buf.ToSqlString(); } - // Parameters inside function are not supported private void RenderFunctions(IList<SqlString> tokens) { for (int tokenIdx = 0; tokenIdx < tokens.Count; tokenIdx++) @@ -983,10 +995,10 @@ if (func != null) { int flTokenIdx = tokenIdx; - string renderedFunction = RenderFunctionClause(func, (IList)tokens, ref flTokenIdx); - // At this point we have the trunk that represent the function with it's parameters enclosed - // in paren. Now all token in the tokens list can be removed from original list because they must - // be replased with the rendered function. + SqlString renderedFunction = RenderFunctionClause(func, tokens, ref flTokenIdx); + // At this point we have the trunk that represents the function with its + // arguments enclosed in parens. Now all token in the tokens list will be + // removed from the original list and replaced with the rendered function. for (int i = 0; i < flTokenIdx - tokenIdx; i++) { tokens.RemoveAt(tokenIdx + 1); @@ -1003,30 +1015,32 @@ /// <param name="tokenIdx">The index of the list that represent the founded function.</param> /// <returns>String trepresentation of each token.</returns> /// <remarks>Each token can be string or SqlString </remarks> - private StringCollection ExtractFunctionClause(IList tokens, ref int tokenIdx) + private IList<SqlString> ExtractFunctionClause(IList<SqlString> tokens, ref int tokenIdx) { - string funcName = tokens[tokenIdx].ToString(); - StringCollection functionTokens = new StringCollection(); + SqlString funcName = tokens[tokenIdx]; + IList<SqlString> functionTokens = new List<SqlString>(); functionTokens.Add(funcName); tokenIdx++; if (tokenIdx >= tokens.Count || !StringHelper.OpenParen.Equals(tokens[tokenIdx].ToString())) { - // All function with parameters have the syntax - // <function name> <left paren> <parameters> <right paren> + // All function with arguments have the syntax + // <function name> <left paren> <arguments> <right paren> throw new QueryException("'(' expected after function " + funcName); } - functionTokens.Add(StringHelper.OpenParen); + functionTokens.Add(new SqlString(StringHelper.OpenParen)); tokenIdx++; int parenCount = 1; for (; tokenIdx < tokens.Count && parenCount > 0; tokenIdx++) { - if (tokens[tokenIdx].ToString().StartsWith(ParserHelper.HqlVariablePrefix) || tokens[tokenIdx].ToString().Equals(StringHelper.SqlParameter)) + if (tokens[tokenIdx].StartsWithCaseInsensitive(ParserHelper.HqlVariablePrefix) || tokens[tokenIdx].ToString().Equals(StringHelper.SqlParameter)) { - throw new QueryException(string.Format("Parameters inside function are not supported (function '{0}').", funcName), - new NotSupportedException()); + functionTokens.Add(SqlString.Parameter); } - functionTokens.Add(tokens[tokenIdx].ToString()); + else + { + functionTokens.Add(tokens[tokenIdx]); + } if (StringHelper.OpenParen.Equals(tokens[tokenIdx].ToString())) { parenCount++; @@ -1044,17 +1058,17 @@ return functionTokens; } - private string RenderFunctionClause(ISQLFunction func, IList tokens, ref int tokenIdx) + private SqlString RenderFunctionClause(ISQLFunction func, IList<SqlString> tokens, ref int tokenIdx) { - StringCollection functionTokens; + IList<SqlString> functionTokens; if (!func.HasArguments) { - // The function don't work with arguments. + // The function doesn't work with arguments. if (func.HasParenthesesIfNoArguments) ExtractFunctionClause(tokens, ref tokenIdx); - // The function render simply translate is't name for a specific dialect. - return func.Render(CollectionHelper.EmptyList, Factory); + // The function render simply translate its name for a specific dialect. + return func.Render(new ArrayList(), Factory); } functionTokens = ExtractFunctionClause(tokens, ref tokenIdx); @@ -1062,8 +1076,8 @@ if (fg == null) fg = new CommonGrammar(); - StringCollection args = new StringCollection(); - StringBuilder argBuf = new StringBuilder(20); + IList args = new ArrayList(); + SqlStringBuilder argBuf = new SqlStringBuilder(); // Extract args spliting first 2 token because are: FuncName( // last token is ')' // To allow expressions like arg (ex:5+5) all tokens between 'argument separator' or @@ -1073,44 +1087,44 @@ // Ex: sum(a.Prop+10), cast(yesterday-1 as date) for (int argIdx = 2; argIdx < functionTokens.Count - 1; argIdx++) { - string token = functionTokens[argIdx]; - if(fg.IsKnownArgument(token)) + object token = functionTokens[argIdx]; + if (fg.IsKnownArgument(token.ToString())) { - if (argBuf.Length > 0) + if (argBuf.Count > 0) { // end of the previous argument - args.Add(argBuf.ToString()); - argBuf = new StringBuilder(20); + args.Add(argBuf.ToSqlString()); + argBuf = new SqlStringBuilder(); } args.Add(token); } - else if (fg.IsSeparator(token)) + else if (fg.IsSeparator(token.ToString())) { // argument end - if (argBuf.Length > 0) + if (argBuf.Count > 0) { - args.Add(argBuf.ToString()); - argBuf = new StringBuilder(20); + args.Add(argBuf.ToSqlString()); + argBuf = new SqlStringBuilder(); } } else { - ISQLFunction nfunc = Factory.SQLFunctionRegistry.FindSQLFunction(token.ToLowerInvariant()); + ISQLFunction nfunc = Factory.SQLFunctionRegistry.FindSQLFunction(token.ToString().ToLowerInvariant()); if (nfunc != null) { // the token is a nested function call - argBuf.Append(RenderFunctionClause(nfunc, functionTokens, ref argIdx)); + argBuf.Add(RenderFunctionClause(nfunc, functionTokens, ref argIdx)); } else { // the token is a part of an argument (every thing else) - argBuf.Append(token); + argBuf.AddObject(token); } } } // Add the last arg - if (argBuf.Length > 0) - args.Add(argBuf.ToString()); + if (argBuf.Count > 0) + args.Add(argBuf.ToSqlString()); return func.Render(args, Factory); } Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -166,8 +166,13 @@ constantToken = true; } - if (constantToken) + if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { + q.AddNamedParameter(token.Substring(1)); + q.AppendScalarSelectParameter(); + } + else if (constantToken) + { q.AppendScalarSelectToken(token); } else @@ -228,11 +233,10 @@ q.AppendScalarSelectToken(token); q.AddSelectScalar(GetFloatingPointConstantType()); } - else if (IsParameter(token)) + else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { - //q.AddNamedParameter(token.Substring(1)); - //q.AppendScalarSelectToken(token); - throw new QueryException("parameters are not supported in SELECT.", new NotSupportedException()); + q.AddNamedParameter(token.Substring(1)); + q.AppendScalarSelectParameter(); } else throw; @@ -244,9 +248,6 @@ #region RegExs private static readonly Regex pathExpressionRegEx = new Regex(@"\A[A-Za-z_][A-Za-z_0-9]*[.][A-Za-z_][A-Za-z_0-9]*\z", RegexOptions.Singleline | RegexOptions.Compiled); private static readonly Regex stringCostantRegEx = new Regex(@"\A'('{2})*([^'\r\n]*)('{2})*([^'\r\n]*)('{2})*'\z", RegexOptions.Singleline | RegexOptions.Compiled); - - private static readonly string paramMatcher = string.Format("\\A([{0}][A-Za-z_][A-Za-z_0-9]*)|[{1}]\\z", ParserHelper.HqlVariablePrefix, StringHelper.SqlParameter); - private static readonly Regex parameterRegEx = new Regex(paramMatcher, RegexOptions.Singleline | RegexOptions.Compiled); #endregion private static bool IsPathExpression(string token) @@ -271,11 +272,6 @@ return double.TryParse(token, NumberStyles.Number, CultureInfo.InvariantCulture, out d); } - private static bool IsParameter(string token) - { - return parameterRegEx.IsMatch(token); - } - private static IType GetIntegerConstantType(string token) { int i; @@ -322,4 +318,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -5,6 +5,7 @@ public interface ISqlStringVisitor { void String(string text); + void String(SqlString sqlString); void Parameter(); } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -12,7 +12,7 @@ { private readonly JoinFragment joins; - private readonly StringBuilder selectBuilder = new StringBuilder(); + private readonly SqlStringBuilder selectBuilder = new SqlStringBuilder(); private readonly SqlStringBuilder whereBuilder = new SqlStringBuilder(); // groupBy, orderBy, and having will for sure have no parameters. @@ -111,9 +111,9 @@ /// /// </summary> /// <param name="fragment"></param> - public void AddSelectFragmentString(string fragment) + public void AddSelectFragmentString(SqlString fragment) { - if (fragment.StartsWith(",")) + if (fragment.StartsWithCaseInsensitive(",")) { fragment = fragment.Substring(1); } @@ -122,12 +122,12 @@ if (fragment.Length > 0) { - if (selectBuilder.Length > 0) + if (selectBuilder.Count > 0) { - selectBuilder.Append(StringHelper.CommaSpace); + selectBuilder.Add(StringHelper.CommaSpace); } - selectBuilder.Append(fragment); + selectBuilder.Add(fragment); } } @@ -138,7 +138,7 @@ /// <param name="alias"></param> public void AddSelectColumn(string columnName, string alias) { - AddSelectFragmentString(columnName + ' ' + alias); + AddSelectFragmentString(new SqlString(columnName + ' ' + alias)); } /// <summary></summary> @@ -224,12 +224,12 @@ from = from.Substring(11); } - builder.Add(selectBuilder.ToString()) + builder.Add(selectBuilder.ToSqlString()) .Add(" from") .Add(from); SqlString part1 = joins.ToWhereFragmentString.Trim(); - SqlString part2 = whereBuilder.ToSqlString().Trim(); + SqlString part2 = whereBuilder.ToSqlString(); bool hasPart1 = part1.Count > 0; bool hasPart2 = part2.Count > 0; @@ -330,4 +330,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -42,7 +42,7 @@ #if DEBUG foreach (object obj in sqlParts) { - Debug.Assert(obj is string || obj is Parameter); + Debug.Assert(obj is string || obj is SqlString || obj is Parameter); } #endif this.sqlParts = sqlParts; @@ -108,10 +108,14 @@ foreach (object part in sqlParts) { + SqlString sqlStringPart = part as SqlString; string stringPart = part as string; - - if (stringPart != null) + if (sqlStringPart != null) { + sqlBuilder.Add(sqlStringPart.Compact()); + } + else if (stringPart != null) + { builder.Append(stringPart); } else @@ -123,7 +127,7 @@ } builder.Length = 0; - sqlBuilder.Add((Parameter) part); + sqlBuilder.Add((Parameter)part); } } @@ -648,10 +652,15 @@ foreach (object part in sqlParts) { string partString = part as string; + SqlString partSqlString = part as SqlString; if (partString != null) { visitor.String(partString); } + else if (partSqlString != null && !SqlString.Parameter.Equals(partSqlString)) + { + visitor.String(partSqlString); + } else { visitor.Parameter(); @@ -726,4 +735,4 @@ return new SubselectClauseExtractor(Compact().sqlParts).GetSqlString(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -333,6 +333,11 @@ parent.Add(text); } + public void String(SqlString sqlString) + { + parent.Add(sqlString); + } + public void Parameter() { parent.AddParameter(); @@ -344,4 +349,4 @@ sqlParts.Clear(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,3 +1,4 @@ +using System; using System.Collections; using NHibernate.Dialect; using NHibernate.Dialect.Function; @@ -17,7 +18,7 @@ static HQLFunctions() { notSupportedStandardFunction.Add("locate", - new System.Type[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect), typeof(FirebirdDialect) }); + new System.Type[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect), typeof(FirebirdDialect), typeof(PostgreSQLDialect) }); notSupportedStandardFunction.Add("bit_length", new System.Type[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect) }); notSupportedStandardFunction.Add("extract", @@ -222,6 +223,36 @@ Animal result = (Animal) s.CreateQuery(hql).UniqueResult(); Assert.AreEqual("abcdef", result.Description); + hql = "from Animal a where substring(a.Description, 2, 3) = ?"; + result = (Animal)s.CreateQuery(hql) + .SetParameter(0, "bcd") + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + + + hql = "from Animal a where substring(a.Description, 2, ?) = 'bcd'"; + result = (Animal)s.CreateQuery(hql) + .SetParameter(0, 3) + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + + + hql = "from Animal a where substring(a.Description, ?, ?) = ?"; + result = (Animal)s.CreateQuery(hql) + .SetParameter(0, 2) + .SetParameter(1, 3) + .SetParameter(2, "bcd") + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + + hql = "select substring(a.Description, ?, ?) from Animal a"; + IList results = s.CreateQuery(hql) + .SetParameter(0, 2) + .SetParameter(1, 3) + .List(); + Assert.AreEqual(1, results.Count); + Assert.AreEqual("bcd", results[0]); + if (twoArgSubstringSupported) { hql = "from Animal a where substring(a.Description, 4) = 'def'"; @@ -560,6 +591,13 @@ result = (Animal)s.CreateQuery(hql).UniqueResult(); Assert.AreEqual("abcdef", result.Description); + // Rendered in WHERE using a property and named param + hql = "from Animal a where cast(:aParam+a.BodyWeight as Double)>0"; + result = (Animal)s.CreateQuery(hql) + .SetDouble("aParam", 2D) + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + // Rendered in WHERE using a property and nested functions hql = "from Animal a where cast(cast(cast(a.BodyWeight as string) as double) as int) = 1"; result = (Animal)s.CreateQuery(hql).UniqueResult(); @@ -595,6 +633,30 @@ Assert.AreEqual(1, l.Count); Assert.AreEqual(129, l[0]); + // Rendered in HAVING using a property and named param (NOT SUPPORTED) + try + { + hql = "select cast(:aParam+a.BodyWeight as int) from Animal a group by cast(:aParam+a.BodyWeight as int) having cast(:aParam+a.BodyWeight as int)>0"; + l = s.CreateQuery(hql).SetInt32("aParam", 10).List(); + Assert.AreEqual(1, l.Count); + Assert.AreEqual(11, l[0]); + } + catch (QueryException ex) + { + if (!(ex.InnerException is NotSupportedException)) + throw; + } + catch (ADOException ex) + { + // This test raises an exception in SQL Server because named + // parameters internally are always positional (@p0, @p1, etc.) + // and named differently hence they mismatch between GROUP BY and HAVING clauses. + if (!ex.InnerException.Message.Equals( + "Column 'Animal.BodyWeight' is invalid in the HAVING clause " + + "because it is not contained in either an aggregate function or the GROUP BY clause.")) + throw; + } + // Rendered in HAVING using a property and nested functions string castExpr = "cast(cast(cast(a.BodyWeight as string) as double) as int)"; hql = string.Format("select {0} from Animal a group by {0} having {0} = 1", castExpr); Modified: trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -16,19 +16,19 @@ Assert.IsTrue(ft.HasArguments); IList args = new ArrayList(); args.Add("'abcd <'"); - Assert.AreEqual("ltrim( 'abcd <' )", ft.Render(args, factoryImpl)); + Assert.AreEqual("ltrim( 'abcd <' )", ft.Render(args, factoryImpl).ToString()); ft = new SQLFunctionTemplate(NHibernateUtil.String, "ltrim( Az?ab )"); Assert.IsFalse(ft.HasArguments); - Assert.AreEqual("ltrim( Az?ab )", ft.Render(args, factoryImpl)); + Assert.AreEqual("ltrim( Az?ab )", ft.Render(args, factoryImpl).ToString()); ft = new SQLFunctionTemplate(NHibernateUtil.String, "function( ?1 )? 5:6"); Assert.IsTrue(ft.HasArguments); - Assert.AreEqual("function( 'abcd <' )? 5:6", ft.Render(args, factoryImpl)); + Assert.AreEqual("function( 'abcd <' )? 5:6", ft.Render(args, factoryImpl).ToString()); ft = new SQLFunctionTemplate(NHibernateUtil.String, "????????1?"); Assert.IsTrue(ft.HasArguments); - Assert.AreEqual("???????'abcd <'?", ft.Render(args, factoryImpl)); + Assert.AreEqual("???????'abcd <'?", ft.Render(args, factoryImpl).ToString()); } [Test] @@ -44,14 +44,14 @@ args.Add("'param2 ab '"); Assert.AreEqual( "replace( replace( rtrim( replace( replace( 'param1 ', ' ', '${space}$' ), 'param2 ab ', ' ' ) ), ' ', 'param2 ab ' ), '${space}$', ' ' )", - ft.Render(args, factoryImpl)); + ft.Render(args, factoryImpl).ToString()); args.Clear(); ft = new SQLFunctionTemplate(NHibernateUtil.String, "?1 ?3 ?2 ?3 ?1"); args.Add(1); args.Add(2); args.Add(3); - Assert.AreEqual("1 3 2 3 1", ft.Render(args, factoryImpl)); + Assert.AreEqual("1 3 2 3 1", ft.Render(args, factoryImpl).ToString()); } //[Test] not required @@ -68,7 +68,7 @@ DateTime.Today.ToString(DateTimeFormatInfo.InvariantInfo), (125.6D).ToString(NumberFormatInfo.InvariantInfo), (0910.123456m).ToString(NumberFormatInfo.InvariantInfo)); - Assert.AreEqual(expected, ft.Render(args, factoryImpl)); + Assert.AreEqual(expected, ft.Render(args, factoryImpl).ToString()); } [Test] @@ -79,13 +79,13 @@ // No Args; 2 params ft = new SQLFunctionTemplate(NHibernateUtil.String, "func(?1,?2)"); - Assert.AreEqual("func(,)", ft.Render(args, factoryImpl)); + Assert.AreEqual("func(,)", ft.Render(args, factoryImpl).ToString()); // Args<params args.Clear(); ft = new SQLFunctionTemplate(NHibernateUtil.String, "func(?1,?2)"); args.Add(1); - Assert.AreEqual("func(1,)", ft.Render(args, factoryImpl)); + Assert.AreEqual("func(1,)", ft.Render(args, factoryImpl).ToString()); // Args>params args.Clear(); @@ -93,7 +93,7 @@ args.Add(1); args.Add(2); args.Add(3); - Assert.AreEqual("func(1,3)", ft.Render(args, factoryImpl)); + Assert.AreEqual("func(1,3)", ft.Render(args, factoryImpl).ToString()); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -3,6 +3,7 @@ using NHibernate.Dialect.Function; using NHibernate.SqlTypes; using NUnit.Framework; +using NHibernate.SqlCommand; namespace NHibernate.Test.HQLFunctionTest { @@ -15,16 +16,16 @@ IList args = new ArrayList(); NoArgSQLFunction nf = new NoArgSQLFunction("noArgs", NHibernateUtil.String); Assert.IsTrue(nf.HasParenthesesIfNoArguments); - Assert.AreEqual("noArgs()", nf.Render(args, factoryImpl)); + Assert.AreEqual("noArgs()", nf.Render(args, factoryImpl).ToString()); nf = new NoArgSQLFunction("noArgs", NHibernateUtil.String, false); Assert.IsFalse(nf.HasParenthesesIfNoArguments); - Assert.AreEqual("noArgs", nf.Render(args, factoryImpl)); + Assert.AreEqual("noArgs", nf.Render(args, factoryImpl).ToString()); args.Add("aparam"); try { - string t = nf.Render(args, factoryImpl); + SqlString t = nf.Render(args, factoryImpl); Assert.Fail("No exception if has argument"); } catch (QueryException) @@ -39,11 +40,11 @@ IList args = new ArrayList(); StandardSQLFunction sf = new StandardSQLFunction("fname"); - Assert.AreEqual("fname()", sf.Render(args, factoryImpl)); + Assert.AreEqual("fname()", sf.Render(args, factoryImpl).ToString()); args.Add(1); args.Add(2); - Assert.AreEqual("fname(1, 2)", sf.Render(args, factoryImpl)); + Assert.AreEqual("fname(1, 2)", sf.Render(args, factoryImpl).ToString()); } [Test] @@ -54,7 +55,7 @@ CastFunction cf = new CastFunction(); try { - string t = cf.Render(args, factoryImpl); + SqlString t = cf.Render(args, factoryImpl); Assert.Fail("No exception if no argument"); } catch (QueryException) @@ -66,14 +67,14 @@ args.Add("long"); string expected = string.Format("cast({0} as {1})", args[0], factoryImpl.Dialect.GetCastTypeName(SqlTypeFactory.Int64)); - Assert.AreEqual(expected, cf.Render(args, factoryImpl)); + Assert.AreEqual(expected, cf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("'123'"); args.Add("NO_TYPE"); try { - string t = cf.Render(args, factoryImpl); + SqlString t = cf.Render(args, factoryImpl); Assert.Fail("Ivalid type accepted"); } catch (QueryException) @@ -88,16 +89,16 @@ IList args = new ArrayList(); VarArgsSQLFunction vf = new VarArgsSQLFunction("(", " || ", ")"); - Assert.AreEqual("()", vf.Render(args, factoryImpl)); + Assert.AreEqual("()", vf.Render(args, factoryImpl).ToString()); args.Add("va1"); - Assert.AreEqual("(va1)", vf.Render(args, factoryImpl)); + Assert.AreEqual("(va1)", vf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); args.Add("va3"); - Assert.AreEqual("(va1 || va2 || va3)", vf.Render(args, factoryImpl)); + Assert.AreEqual("(va1 || va2 || va3)", vf.Render(args, factoryImpl).ToString()); } [Test] @@ -107,13 +108,13 @@ NvlFunction nf = new NvlFunction(); args.Add("va1"); - Assert.AreEqual("va1", nf.Render(args, factoryImpl)); + Assert.AreEqual("va1", nf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); args.Add("va3"); - Assert.AreEqual("nvl(va1, nvl(va2, va3))", nf.Render(args, factoryImpl)); + Assert.AreEqual("nvl(va1, nvl(va2, va3))", nf.Render(args, factoryImpl).ToString()); } [Test] @@ -124,13 +125,13 @@ PositionSubstringFunction psf = new PositionSubstringFunction(); args.Add("'a'"); args.Add("va2"); - Assert.AreEqual("position('a' in va2)", psf.Render(args, factoryImpl)); + Assert.AreEqual("position('a' in va2)", psf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("'a'"); args.Add("va2"); args.Add("2"); - Assert.AreEqual("(position('a' in substring(va2, 2))+2-1)", psf.Render(args, factoryImpl)); + Assert.AreEqual("(position('a' in substring(va2, 2))+2-1)", psf.Render(args, factoryImpl).ToString()); } [Test] @@ -145,19 +146,19 @@ ClassicSumFunction csf = new ClassicSumFunction(); args.Add("va1"); - Assert.AreEqual("sum(va1)", csf.Render(args, factoryImpl)); + Assert.AreEqual("sum(va1)", csf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("distinct"); args.Add("va2"); - Assert.AreEqual("sum(distinct va2)", csf.Render(args, factoryImpl)); + Assert.AreEqual("sum(distinct va2)", csf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); try { - string t = csf.Render(args, factoryImpl); + SqlString t = csf.Render(args, factoryImpl); Assert.Fail("No exception 2 argument without <setquantifier>:" + t); } catch (QueryException) @@ -175,18 +176,18 @@ ClassicCountFunction ccf = new ClassicCountFunction(); args.Add("va1"); - Assert.AreEqual("count(va1)", ccf.Render(args, factoryImpl)); + Assert.AreEqual("count(va1)", ccf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("*"); - Assert.AreEqual("count(*)", ccf.Render(args, factoryImpl)); + Assert.AreEqual("count(*)", ccf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); try { - string t = ccf.Render(args, factoryImpl); + SqlString t = ccf.Render(args, factoryImpl); Assert.Fail("No exception 2 argument without <setquantifier>:" + t); } catch (QueryException) @@ -207,19 +208,19 @@ ClassicAvgFunction caf = new ClassicAvgFunction(); args.Add("va1"); - Assert.AreEqual("avg(va1)", caf.Render(args, factoryImpl)); + Assert.AreEqual("avg(va1)", caf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("distinct"); args.Add("va2"); - Assert.AreEqual("avg(distinct va2)", caf.Render(args, factoryImpl)); + Assert.AreEqual("avg(distinct va2)", caf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); try { - string t = caf.Render(args, factoryImpl); + SqlString t = caf.Render(args, factoryImpl); Assert.Fail("No exception 2 argument without <setquantifier>:" + t); } catch (QueryException) @@ -235,19 +236,19 @@ ClassicAggregateFunction caf = new ClassicAggregateFunction("max", false); args.Add("va1"); - Assert.AreEqual("max(va1)", caf.Render(args, factoryImpl)); + Assert.AreEqual("max(va1)", caf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("d... [truncated message content] |