⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 whereparser.cs

📁 NHibernate NET开发者所需的
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using System.Collections.Generic;
using System.Text;
using Iesi.Collections.Generic;
using NHibernate.Engine;
using NHibernate.Hql.Util;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;

namespace NHibernate.Hql.Classic
{
	/// <summary> Parses the where clause of a hibernate query and translates it to an
	/// SQL where clause.
	/// </summary>
	// We should reengineer this class so that, rather than the current ad -
	// hoc linear approach to processing a stream of tokens, we instead
	// build up a tree of expressions.
	// We would probably refactor to have LogicParser (builds a tree of simple
	// expressions connected by and, or, not), ExpressionParser (translates
	// from OO terms like foo, foo.Bar, foo.Bar.Baz to SQL terms like
	// FOOS.ID, FOOS.BAR_ID, etc) and PathExpressionParser (which does much
	// the same thing it does now)
	public class WhereParser : IParser
	{
		private readonly PathExpressionParser pathExpressionParser = new PathExpressionParser();

		private static readonly ISet<string> expressionTerminators = new HashedSet<string>(); //tokens that close a sub expression
		private static readonly ISet<string> expressionOpeners = new HashedSet<string>(); //tokens that open a sub expression

		private static readonly ISet<string> booleanOperators = new HashedSet<string>();
		                    //tokens that would indicate a sub expression is a boolean expression

		private static readonly Dictionary<string, string> negations = new Dictionary<string, string>();

		// To parse correctly the functions TRIM and EXTRACT (Note subselect inside TRIM is not supported)
		private static readonly ISet<string> specialFunctions = new HashedSet<string>();

		public WhereParser()
		{
			pathExpressionParser.UseThetaStyleJoin = true;
		}

		static WhereParser()
		{
			expressionTerminators.Add("and");
			expressionTerminators.Add("or");
			expressionTerminators.Add(StringHelper.ClosedParen);
			//expressionTerminators.Add(","); // deliberately excluded

			expressionOpeners.Add("and");
			expressionOpeners.Add("or");
			expressionOpeners.Add(StringHelper.OpenParen);
			//expressionOpeners.Add(","); // deliberately excluded

			booleanOperators.Add("<");
			booleanOperators.Add("=");
			booleanOperators.Add(">");
			booleanOperators.Add("#");
			booleanOperators.Add("~");
			booleanOperators.Add("like");
			booleanOperators.Add("ilike");
			booleanOperators.Add("is");
			booleanOperators.Add("in");
			booleanOperators.Add("any");
			booleanOperators.Add("some");
			booleanOperators.Add("all");
			booleanOperators.Add("exists");
			booleanOperators.Add("between");
			booleanOperators.Add("<=");
			booleanOperators.Add(">=");
			booleanOperators.Add("=>");
			booleanOperators.Add("=<");
			booleanOperators.Add("!=");
			booleanOperators.Add("<>");
			booleanOperators.Add("!#");
			booleanOperators.Add("!~");
			booleanOperators.Add("!<");
			booleanOperators.Add("!>");
			booleanOperators.Add("is not");
			booleanOperators.Add("not like");
			booleanOperators.Add("not ilike");
			booleanOperators.Add("not in");
			booleanOperators.Add("not between");
			booleanOperators.Add("not exists");

			negations.Add("and", "or");
			negations.Add("or", "and");
			negations.Add("<", ">=");
			negations.Add("=", "<>");
			negations.Add(">", "<=");
			negations.Add("#", "!#");
			negations.Add("~", "!~");
			negations.Add("like", "not like");
			negations.Add("ilike", "not ilike");
			negations.Add("is", "is not");
			negations.Add("in", "not in");
			negations.Add("exists", "not exists");
			negations.Add("between", "not between");
			negations.Add("<=", ">");
			negations.Add(">=", "<");
			negations.Add("=>", "<");
			negations.Add("=<", ">");
			negations.Add("!=", "=");
			negations.Add("<>", "=");
			negations.Add("!#", "#");
			negations.Add("!~", "~");
			negations.Add("!<", ">=");
			negations.Add("!>", "<=");
			negations.Add("is not", "is");
			negations.Add("not like", "like");
			negations.Add("not in", "in");
			negations.Add("not between", "between");
			negations.Add("not exists", "exists");

			specialFunctions.Add("trim");
			specialFunctions.Add("extract");

		}

		// Handles things like:
		// a and b or c
		// a and ( b or c )
		// not a and not b
		// not ( a and b )
		// x between y and z            (overloaded "and")
		// x in ( a, b, c )             (overloaded brackets)
		// not not a
		// a is not null                (overloaded "not")
		// etc......
		// and expressions like
		// foo = bar                    (maps to: foo.id = bar.id)
		// foo.Bar = 'foo'              (maps to: foo.bar = 'foo')
		// foo.Bar.Baz = 1.0            (maps to: foo.bar = bar.id and bar.baz = 1.0)
		// 1.0 = foo.Bar.Baz            (maps to: bar.baz = 1.0 and foo.Bar = bar.id)
		// foo.Bar.Baz = a.B.C          (maps to: bar.Baz = b.C and foo.Bar = bar.id and a.B = b.id)
		// foo.Bar.Baz + a.B.C          (maps to: bar.Baz + b.C and foo.Bar = bar.id and a.B = b.id)
		// ( foo.Bar.Baz + 1.0 ) < 2.0  (maps to: ( bar.Baz + 1.0 ) < 2.0 and foo.Bar = bar.id)

		private bool betweenSpecialCase = false; //Inside a BETWEEN ... AND ... expression
		private bool negated = false;

		private bool inSubselect = false;
		private int bracketsSinceSelect = 0;
		private StringBuilder subselect;

		private bool isInSpecialFunctionClause = false;
		private int specialFunctionParenCount = 0;

		private bool expectingPathContinuation = false;
		private int expectingIndex = 0;

		// The following variables are stacks that keep information about each subexpression
		// in the list of nested subexpressions we are currently processing.

		//were an odd or even number of NOTs encountered
		private readonly List<bool> nots = new List<bool>();

		//the join string built up by compound paths inside this expression 
		private readonly List<SqlStringBuilder> joins = new List<SqlStringBuilder>();

		//a flag indicating if the subexpression is known to be boolean		
		private readonly List<bool> booleanTests = new List<bool>();

		private string GetElementName(PathExpressionParser.CollectionElement element, QueryTranslator q)
		{
			string name;
			if (element.IsOneToMany)
			{
				name = element.Alias;
			}
			else
			{
				IType type = element.Type;

				if (type.IsEntityType)
				{
					//ie. a many-to-many
					string clazz = ((EntityType) type).GetAssociatedEntityName();
					name = pathExpressionParser.ContinueFromManyToMany(clazz, element.ElementColumns, q);
				}
				else
				{
					throw new QueryException("illegally dereferenced collection element");
				}
			}
			return name;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="token"></param>
		/// <param name="q"></param>
		public void Token(string token, QueryTranslator q)
		{
			string lcToken = token.ToLowerInvariant();

			//Cope with [,]

			if (token.Equals("[") && !expectingPathContinuation)
			{
				expectingPathContinuation = false;
				if (expectingIndex == 0)
				{
					throw new QueryException("unexpected [");
				}
				return;
			}
			else if (token.Equals("]"))
			{
				expectingIndex--;
				expectingPathContinuation = true;
				return;
			}

			//Cope with a continued path expression (ie. ].baz)
			if (expectingPathContinuation)
			{
				if (ContinuePathExpression(token, q)) return;
			}

			//Cope with a subselect
			if (!inSubselect && (lcToken.Equals("select") || (lcToken.Equals("from") && !isInSpecialFunctionClause)))
			{
				inSubselect = true;
				subselect = new StringBuilder(20);
			}
			if (inSubselect && token.Equals(StringHelper.ClosedParen))
			{
				bracketsSinceSelect--;

				if (bracketsSinceSelect == -1)
				{
					QueryTranslator subq = new QueryTranslator(q.Factory, subselect.ToString(), q.EnabledFilters);
					try
					{
						subq.Compile(q);
					}
					catch (MappingException me)
					{
						throw new QueryException("MappingException occurred compiling subquery", me);
					}

					AppendToken(q, subq.SqlString);
					inSubselect = false;
					bracketsSinceSelect = 0;
				}
			}
			if (inSubselect)
			{
				if (token.Equals(StringHelper.OpenParen))
				{
					bracketsSinceSelect++;
				}
				subselect.Append(token).Append(' ');
				return;
			}

			//Cope with special cases of AND, NOT, ()
			SpecialCasesBefore(lcToken);

			//Close extra brackets we opened
			if (!betweenSpecialCase && expressionTerminators.Contains(lcToken))
			{
				CloseExpression(q, lcToken);
			}

			//take note when this is a boolean expression

			if (booleanOperators.Contains(lcToken))
			{
				booleanTests.RemoveAt(booleanTests.Count - 1);
				booleanTests.Add(true);
			}

			if (lcToken.Equals("not"))
			{
				nots[nots.Count - 1] = !nots[nots.Count - 1];
				negated = !negated;
				return; //NOTE: early return
			}

			if (!isInSpecialFunctionClause && specialFunctions.Contains(lcToken))
			{
				isInSpecialFunctionClause = true;
			}
			if (isInSpecialFunctionClause && token.Equals(StringHelper.OpenParen))
			{
				specialFunctionParenCount++;
			}
			if (isInSpecialFunctionClause && token.Equals(StringHelper.ClosedParen))
			{
				specialFunctionParenCount--;
				isInSpecialFunctionClause = specialFunctionParenCount > 0;
			}
			//process a token, mapping OO path expressions to SQL expressions
			DoToken(token, q);

			//Open any extra brackets we might need.

			if (!betweenSpecialCase && expressionOpeners.Contains(lcToken))
			{
				OpenExpression(q, lcToken);
			}

			//Cope with special cases of AND, NOT, )
			SpecialCasesAfter(lcToken);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		public void Start(QueryTranslator q)
		{
			Token(StringHelper.OpenParen, q);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>

⌨️ 快捷键说明

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