ansitrimemulationfunction.cs

来自「NHibernate NET开发者所需的」· CS 代码 · 共 213 行

CS
213
字号
using System;
using System.Collections;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;
using System.Text.RegularExpressions;

namespace NHibernate.Dialect.Function
{
	/// <summary>
	/// A SQLFunction implementation that emulates the ANSI SQL trim function
	/// on dialects which do not support the full definition.  However, this function
	/// definition does assume the availability of ltrim, rtrim, and replace functions
	/// which it uses in various combinations to emulate the desired ANSI trim()
	/// functionality.
	/// </summary>
	public class AnsiTrimEmulationFunction : ISQLFunction, IFunctionGrammar
	{
		private static readonly ISQLFunction LeadingSpaceTrim = new SQLFunctionTemplate(NHibernateUtil.String, "ltrim( ?1 )");
		private static readonly ISQLFunction TrailingSpaceTrim = new SQLFunctionTemplate(NHibernateUtil.String, "rtrim( ?1 )");

		private static readonly ISQLFunction BothSpaceTrim =
			new SQLFunctionTemplate(NHibernateUtil.String, "ltrim( rtrim( ?1 ) )");

		private static readonly ISQLFunction BothSpaceTrimFrom =
			new SQLFunctionTemplate(NHibernateUtil.String, "ltrim( rtrim( ?2 ) )");

		private static readonly ISQLFunction LeadingTrim =
			new SQLFunctionTemplate(NHibernateUtil.String,
			                        "replace( replace( rtrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ), ' ', ?2 ), '${space}$', ' ' )");

		private static readonly ISQLFunction TrailingTrim =
			new SQLFunctionTemplate(NHibernateUtil.String,
			                        "replace( replace( ltrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ), ' ', ?2 ), '${space}$', ' ' )");

		private static readonly ISQLFunction BothTrim =
			new SQLFunctionTemplate(NHibernateUtil.String,
			                        "replace( replace( ltrim( rtrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ) ), ' ', ?2 ), '${space}$', ' ' )");

		#region ISQLFunction Members

		public IType ReturnType(IType columnType, IMapping mapping)
		{
			return NHibernateUtil.String;
		}

		public bool HasArguments
		{
			get { return true; }
		}

		public bool HasParenthesesIfNoArguments
		{
			get { return true; }
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="args"></param>
		/// <param name="factory"></param>
		/// <returns></returns>
		/// <remarks>
		/// according to both the ANSI-SQL and EJB3 specs, trim can either take
		/// exactly one parameter or a variable number of parameters between 1 and 4.
		/// from the SQL spec:
		/// <![CDATA[
		/// <trim function> ::=
		///      TRIM <left paren> <trim operands> <right paren>
		///
		/// <trim operands> ::=
		///      [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
		///
		/// <trim specification> ::=
		///      LEADING
		///      | TRAILING
		///      | BOTH
		/// ]]>
		/// If only trim specification is omitted, BOTH is assumed;
		/// if trim character is omitted, space is assumed
		/// </remarks>
		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 = args[0].ToString();

			if (args.Count == 1)
			{
				// we have the form: trim(trimSource)
				//      so we trim leading and trailing spaces
				return BothSpaceTrim.Render(args, factory);
			}
			else if (StringHelper.EqualsCaseInsensitive("from", firstArg))
			{
				// we have the form: trim(from trimSource).
				//      This is functionally equivalent to trim(trimSource)
				return BothSpaceTrimFrom.Render(args, factory);
			}
			else
			{
				// otherwise, a trim-specification and/or a trim-character
				// have been specified;  we need to decide which options
				// are present and "do the right thing"
				bool leading = true; // should leading trim-characters be trimmed?
				bool trailing = true; // should trailing trim-characters be trimmed?
				string trimCharacter = null; // the trim-character
				object trimSource = null; // the trim-source

				// potentialTrimCharacterArgIndex = 1 assumes that a
				// trim-specification has been specified.  we handle the
				// exception to that explicitly
				int potentialTrimCharacterArgIndex = 1;
				if (StringHelper.EqualsCaseInsensitive("leading", firstArg))
				{
					trailing = false;
				}
				else if (StringHelper.EqualsCaseInsensitive("trailing", firstArg))
				{
					leading = false;
				}
				else if (StringHelper.EqualsCaseInsensitive("both", firstArg))
				{
				}
				else
				{
					potentialTrimCharacterArgIndex = 0;
				}

				object potentialTrimCharacter = args[potentialTrimCharacterArgIndex];
				if (StringHelper.EqualsCaseInsensitive("from", potentialTrimCharacter.ToString()))
				{
					trimCharacter = "' '";
					trimSource = args[potentialTrimCharacterArgIndex + 1];
				}
				else if (potentialTrimCharacterArgIndex + 1 >= args.Count)
				{
					trimCharacter = "' '";
					trimSource = potentialTrimCharacter;
				}
				else
				{
					trimCharacter = potentialTrimCharacter.ToString();
					if (StringHelper.EqualsCaseInsensitive("from", args[potentialTrimCharacterArgIndex + 1].ToString()))
					{
						trimSource = args[potentialTrimCharacterArgIndex + 2];
					}
					else
					{
						trimSource = args[potentialTrimCharacterArgIndex + 1];
					}
				}

				IList argsToUse = new ArrayList();
				argsToUse.Add(trimSource);
				argsToUse.Add(trimCharacter);

				if (trimCharacter.Equals("' '"))
				{
					if (leading && trailing)
					{
						return BothSpaceTrim.Render(argsToUse, factory);
					}
					else if (leading)
					{
						return LeadingSpaceTrim.Render(argsToUse, factory);
					}
					else
					{
						return TrailingSpaceTrim.Render(argsToUse, factory);
					}
				}
				else
				{
					if (leading && trailing)
					{
						return BothTrim.Render(argsToUse, factory);
					}
					else if (leading)
					{
						return LeadingTrim.Render(argsToUse, factory);
					}
					else
					{
						return TrailingTrim.Render(argsToUse, factory);
					}
				}
			}
		}

		#endregion

		#region IFunctionGrammar Members

		bool IFunctionGrammar.IsSeparator(string token)
		{
			return false;
		}

		bool IFunctionGrammar.IsKnownArgument(string token)
		{
			return Regex.IsMatch(token, "LEADING|TRAILING|BOTH|FROM",
				RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
		}

		#endregion
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?