public Dictionary <IASTNode, IASTNode[]> Process(IASTNode tree) { foreach (var querySource in new QuerySourceDetector(tree).LocateQuerySources()) { var className = GetClassName(querySource); var classType = _sessionFactoryHelper.GetImportedClass(className); AddImplementorsToMap(querySource, classType == null ? className : classType.FullName); } return(_map); }
/// <summary> /// Handle Hibernate "implicit" polymorphism, by translating the query string into /// several "concrete" queries against mapped classes. /// </summary> /// <param name="query"></param> /// <param name="factory"></param> /// <returns></returns> /// <exception cref="NHibernate.MappingException"/> public static string[] ConcreteQueries(string query, ISessionFactoryImplementor factory) { //scan the query string for class names appearing in the from clause and replace //with all persistent implementors of the class/interface, returning multiple //query strings (make sure we don't pick up a class in the select clause!) //TODO: this is one of the ugliest and most fragile pieces of code in Hibernate.... SessionFactoryHelper helper = new SessionFactoryHelper(factory); string[] tokens = StringHelper.Split(StringHelper.WhiteSpace + "(),", query, true); if (tokens.Length == 0) { return(new String[] { query }); // just especially for the trivial collection filter } ArrayList placeholders = new ArrayList(); ArrayList replacements = new ArrayList(); StringBuilder templateQuery = new StringBuilder(40); int count = 0; string last = null; int nextIndex = 0; string next = null; templateQuery.Append(tokens[0]); bool isSelectClause = StringHelper.EqualsCaseInsensitive("select", tokens[0]); for (int i = 1; i < tokens.Length; i++) { //update last non-whitespace token, if necessary if (!ParserHelper.IsWhitespace(tokens[i - 1])) { last = tokens[i - 1].ToLowerInvariant(); } // select-range is terminated by declaration of "from" isSelectClause = !StringHelper.EqualsCaseInsensitive("from", tokens[i]); string token = tokens[i]; if (!ParserHelper.IsWhitespace(token) || last == null) { //scan for next non-whitespace token if (nextIndex <= i) { for (nextIndex = i + 1; nextIndex < tokens.Length; nextIndex++) { next = tokens[nextIndex].ToLowerInvariant(); if (!ParserHelper.IsWhitespace(next)) { break; } } } // TODO H3.2 Different behavior // NHb: This block is not an exactly port from H3.2 but a port from previous implementation of QueryTranslator if (((last != null && beforeClassTokens.Contains(last)) && (next == null || !notAfterClassTokens.Contains(next))) || PathExpressionParser.EntityClass.Equals(last)) { System.Type clazz = helper.GetImportedClass(token); if (clazz != null) { string[] implementors = factory.GetImplementors(clazz.FullName); string placeholder = "$clazz" + count++ + "$"; if (implementors != null) { placeholders.Add(placeholder); replacements.Add(implementors); } token = placeholder; //Note this!! } } } templateQuery.Append(token); } string[] results = StringHelper.Multiply(templateQuery.ToString(), placeholders.GetEnumerator(), replacements.GetEnumerator()); if (results.Length == 0) { log.Warn("no persistent classes found for query class: " + query); } return(results); }
private void DoToken(string token, QueryTranslator q) { SessionFactoryHelper helper = new SessionFactoryHelper(q.Factory); if (q.IsName(StringHelper.Root(token))) //path expression { DoPathExpression(q.Unalias(token), q); } else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) //named query parameter { var name = token.Substring(1); // this is only a temporary parameter to help with the parsing of hql - // when the type becomes known then this will be converted to its real // parameter type. AppendToken(q, q.GetNamedParameter(name)); } else if (token.Equals(StringHelper.SqlParameter)) { //if the token is a "?" then we have a Parameter so convert it to a SqlCommand.Parameter // instead of appending a "?" to the WhereTokens AppendToken(q, q.GetPositionalParameter()); } else { IQueryable persister = q.GetPersisterUsingImports(token); if (persister != null) // the name of a class { string discrim = persister.DiscriminatorSQLValue; if (InFragment.Null == discrim || InFragment.NotNull == discrim) { throw new QueryException("subclass test not allowed for null or not null discriminator"); } AppendToken(q, discrim); } else { object constant; string fieldName = null; System.Type importedType = null; int indexOfDot = token.IndexOf(StringHelper.Dot); // don't even bother to do the lookups if the indexOfDot is not // greater than -1. This will save all the string modifications. // This allows us to resolve to the full type before obtaining the value e.g. FooStatus.OFF -> NHibernate.Model.FooStatus.OFF if (indexOfDot > -1) { fieldName = StringHelper.Unqualify(token); string typeName = StringHelper.Qualifier(token); importedType = helper.GetImportedClass(typeName); } if (indexOfDot > -1 && importedType != null && (constant = ReflectHelper.GetConstantValue(importedType, fieldName)) != null) { // need to get the NHibernate Type so we can convert the Enum or field from // a class into it's string representation for hql. IType type; try { type = TypeFactory.HeuristicType(constant.GetType().AssemblyQualifiedName); } catch (MappingException me) { throw new QueryException(me); } if (type == null) { throw new QueryException(string.Format("Could not determin the type of: {0}", token)); } try { AppendToken(q, ((ILiteralType)type).ObjectToSQLString(constant, q.Factory.Dialect)); } catch (Exception e) { throw new QueryException("Could not format constant value to SQL literal: " + token, e); } } else { //anything else string negatedToken = null; if (negated) { negations.TryGetValue(token.ToLowerInvariant(), out negatedToken); } if (negatedToken != null && (!betweenSpecialCase || !"or".Equals(negatedToken))) { AppendToken(q, negatedToken); } else { AppendToken(q, token); } } } } }
public void Token(string token, QueryTranslator q) { SessionFactoryHelper helper = new SessionFactoryHelper(q.Factory); string lctoken = token.ToLowerInvariant(); if (first) { first = false; if ("distinct".Equals(lctoken)) { q.Distinct = true; return; } else if ("all".Equals(lctoken)) { q.Distinct = false; return; } } if (afterNew) { afterNew = false; holderClass = helper.GetImportedClass(token); if (holderClass == null) { throw new QueryException("class not found: " + token); } q.HolderClass = holderClass; insideNew = true; } else if (token.Equals(StringHelper.Comma)) { if (readyForAliasOrExpression) { throw new QueryException("alias or expression expected in SELECT"); } q.AppendScalarSelectToken(StringHelper.CommaSpace); readyForAliasOrExpression = true; } else if ("new".Equals(lctoken)) { afterNew = true; readyForAliasOrExpression = false; } else if (StringHelper.OpenParen.Equals(token)) { parenCount++; if (!funcStack.HasFunctions && holderClass != null && !readyForAliasOrExpression) { //opening paren in new Foo ( ... ) readyForAliasOrExpression = true; } else if (funcStack.HasFunctions) { q.AppendScalarSelectToken(token); } else { throw new QueryException("HQL function expected before '(' in SELECT clause."); } readyForAliasOrExpression = true; } else if (StringHelper.ClosedParen.Equals(token)) { parenCount--; if (parenCount < 0) { throw new QueryException("'(' expected before ')' in SELECT clause."); } if (insideNew && !funcStack.HasFunctions && !readyForAliasOrExpression) { //if we are inside a new Result(), but not inside a nested function insideNew = false; } else if (funcStack.HasFunctions) { q.AppendScalarSelectToken(token); IType scalarType = funcStack.GetReturnType(); funcStack.Pop(); // Can't have an alias or expression right after the closing parenthesis of a function call. readyForAliasOrExpression = false; // if all functions were parsed add the type of the first function in stack if (!funcStack.HasFunctions) { q.AddSelectScalar(scalarType); } } } else if (IsHQLFunction(lctoken, q) && token == q.Unalias(token)) { if (!readyForAliasOrExpression && !funcStack.HasFunctions) { // The syntax control inside a functions is delegated to the render throw new QueryException("',' expected before function in SELECT: " + token); } if (funcStack.HasFunctions && funcStack.FunctionGrammar.IsKnownArgument(lctoken)) { // Some function, like extract, may have KnownArgument with the same name of another function q.AppendScalarSelectToken(token); } else { // Is a nested function funcStack.Push(GetFunction(lctoken, q)); q.AppendScalarSelectToken(token); if (!funcStack.SqlFunction.HasArguments && !funcStack.SqlFunction.HasParenthesesIfNoArguments) { q.AddSelectScalar(funcStack.GetReturnType()); funcStack.Pop(); readyForAliasOrExpression = funcStack.HasFunctions; } } } else if (funcStack.HasFunctions) { bool constantToken = false; var expectedParen = parenCount + ((insideNew) ? -1 : 0); if (!readyForAliasOrExpression && expectedParen != funcStack.NestedFunctionCount) { throw new QueryException("'(' expected after HQL function in SELECT"); } try { ParserHelper.Parse(funcStack.PathExpressionParser, q.Unalias(token), ParserHelper.PathSeparators, q); } catch (QueryException) { if (IsPathExpression(token)) { throw; } // If isn't a path the token is added like part of function arguments constantToken = true; } if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { string name = token.Substring(1); q.AppendScalarSelectParameter(name); } else if (token.Equals(StringHelper.SqlParameter)) { q.AppendScalarSelectParameter(); } else if (constantToken) { q.AppendScalarSelectToken(token); } else { if (funcStack.PathExpressionParser.IsCollectionValued) { q.AddCollection( funcStack.PathExpressionParser.CollectionName, funcStack.PathExpressionParser.CollectionRole); } q.AppendScalarSelectToken(funcStack.PathExpressionParser.WhereColumn); funcStack.PathExpressionParser.AddAssociation(q); } // after a function argument readyForAliasOrExpression = false; } else { if (!readyForAliasOrExpression) { throw new QueryException("',' expected in SELECT before:" + token); } try { //High probablly to find a valid pathExpression ParserHelper.Parse(pathExpressionParser, q.Unalias(token), ParserHelper.PathSeparators, q); if (pathExpressionParser.IsCollectionValued) { q.AddCollection( pathExpressionParser.CollectionName, pathExpressionParser.CollectionRole); } else if (pathExpressionParser.WhereColumnType.IsEntityType) { q.AddSelectClass(pathExpressionParser.SelectName); } q.AppendScalarSelectTokens(pathExpressionParser.WhereColumns); q.AddSelectScalar(pathExpressionParser.WhereColumnType); pathExpressionParser.AddAssociation(q); } catch (QueryException) { // Accept costants in SELECT: NH-280 // TODO: Parse a costant expression like 5+3+8 (now is not supported in SELECT) if (IsStringCostant(token)) { q.AppendScalarSelectToken(token); q.AddSelectScalar(NHibernateUtil.String); } else if (IsIntegerConstant(token)) { q.AppendScalarSelectToken(token); q.AddSelectScalar(GetIntegerConstantType(token)); } else if (IsFloatingPointConstant(token)) { q.AppendScalarSelectToken(token); q.AddSelectScalar(GetFloatingPointConstantType()); } else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { string name = token.Substring(1); q.AppendScalarSelectParameter(name); } else if (token.Equals(StringHelper.SqlParameter)) { q.AppendScalarSelectParameter(); } else { throw; } } readyForAliasOrExpression = false; } }