private FromElement CreateCollectionJoin(JoinSequence collectionJoinSequence, string tableAlias) { string text = _queryableCollection.TableName; IASTNode ast = CreateFromElement(text); FromElement destination = (FromElement)ast; IType elementType = _queryableCollection.ElementType; if (elementType.IsCollectionType) { throw new SemanticException("Collections of collections are not supported!"); } destination.InitializeCollection(_fromClause, _classAlias, tableAlias); destination.Type = HqlSqlWalker.JOIN_FRAGMENT; // Tag this node as a JOIN. destination.SetIncludeSubclasses(false); // Don't include subclasses in the join. destination.CollectionJoin = true; // This is a clollection join. destination.JoinSequence = collectionJoinSequence; destination.SetOrigin(_origin, false); destination.CollectionTableAlias = tableAlias; // origin.addDestination( destination ); // This was the cause of HHH-242 // origin.setType( FROM_FRAGMENT ); // Set the parent node type so that the AST is properly formed. _origin.Text = ""; // The destination node will have all the FROM text. _origin.CollectionJoin = true; // The parent node is a collection join too (voodoo - see JoinProcessor) _fromClause.AddCollectionJoinFromElementByPath(_path, destination); _fromClause.Walker.AddQuerySpaces(_queryableCollection.CollectionSpaces); return(destination); }
/// <summary> /// Generate a join sequence representing the given association type. /// </summary> /// <param name="implicitJoin">Should implicit joins (theta-style) or explicit joins (ANSI-style) be rendered</param> /// <param name="associationType">The type representing the thing to be joined into.</param> /// <param name="tableAlias">The table alias to use in qualifing the join conditions</param> /// <param name="joinType">The type of join to render (inner, outer, etc)</param> /// <param name="columns">The columns making up the condition of the join.</param> /// <returns>The generated join sequence.</returns> public JoinSequence CreateJoinSequence(bool implicitJoin, IAssociationType associationType, string tableAlias, JoinType joinType, string[] columns) { JoinSequence joinSequence = CreateJoinSequence(); joinSequence.SetUseThetaStyle(implicitJoin); // Implicit joins use theta style (WHERE pk = fk), explicit joins use JOIN (after from) joinSequence.AddJoin( associationType, tableAlias, joinType, columns ); return joinSequence; }
private FromElement CreateManyToMany( string role, string associatedEntityName, string roleAlias, IEntityPersister entityPersister, EntityType type, JoinType joinType) { FromElement elem; SessionFactoryHelperExtensions sfh = _fromClause.SessionFactoryHelper; if (_inElementsFunction /*implied*/) { // For implied many-to-many, just add the end join. JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); elem = CreateJoin(associatedEntityName, roleAlias, joinSequence, type, true); } else { // For an explicit many-to-many relationship, add a second join from the intermediate // (many-to-many) table to the destination table. Also, make sure that the from element's // idea of the destination is the destination table. string tableAlias = _fromClause.AliasGenerator.CreateName(entityPersister.EntityName); string[] secondJoinColumns = sfh.GetCollectionElementColumns(role, roleAlias); // Add the second join, the one that ends in the destination table. JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); joinSequence.AddJoin(sfh.GetElementAssociationType(_collectionType), tableAlias, joinType, secondJoinColumns); elem = CreateJoin(associatedEntityName, tableAlias, joinSequence, type, false); elem.UseFromFragment = true; } return(elem); }
private FromElement CreateEntityAssociation( string role, string roleAlias, JoinType joinType) { FromElement elem; IQueryable entityPersister = (IQueryable)_queryableCollection.ElementPersister; string associatedEntityName = entityPersister.EntityName; // Get the class name of the associated entity. if (_queryableCollection.IsOneToMany) { if (Log.IsDebugEnabled) { Log.Debug("createEntityAssociation() : One to many - path = " + _path + " role = " + role + " associatedEntityName = " + associatedEntityName); } JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); elem = CreateJoin(associatedEntityName, roleAlias, joinSequence, (EntityType)_queryableCollection.ElementType, false); } else { if (Log.IsDebugEnabled) { Log.Debug("createManyToMany() : path = " + _path + " role = " + role + " associatedEntityName = " + associatedEntityName); } elem = CreateManyToMany(role, associatedEntityName, roleAlias, entityPersister, (EntityType)_queryableCollection.ElementType, joinType); _fromClause.Walker.AddQuerySpaces(_queryableCollection.CollectionSpaces); } elem.CollectionTableAlias = roleAlias; return(elem); }
public FromElement CreateCollectionElementsJoin(IQueryableCollection queryableCollection, String collectionName) { JoinSequence collectionJoinSequence = _fromClause.SessionFactoryHelper.CreateCollectionJoinSequence(queryableCollection, collectionName); _queryableCollection = queryableCollection; return(CreateCollectionJoin(collectionJoinSequence, null)); }
/// <summary> /// /// </summary> /// <param name="q"></param> public void Start(QueryTranslator q) { if (!continuation) { Reset(q); path.Length = 0; joinSequence = new JoinSequence(q.Factory).SetUseThetaStyle(useThetaStyleJoin); } }
public FromElement CreateElementJoin(IQueryableCollection queryableCollection) { _implied = true; //TODO: always true for now, but not if we later decide to support elements() in the from clause _inElementsFunction = true; IType elementType = queryableCollection.ElementType; if (!elementType.IsEntityType) { throw new InvalidOperationException("Cannot create element join for a collection of non-entities!"); } _queryableCollection = queryableCollection; SessionFactoryHelperExtensions sfh = _fromClause.SessionFactoryHelper; IEntityPersister entityPersister = queryableCollection.ElementPersister; string tableAlias = _fromClause.AliasGenerator.CreateName(entityPersister.EntityName); string associatedEntityName = entityPersister.EntityName; IEntityPersister targetEntityPersister = sfh.RequireClassPersister(associatedEntityName); // Create the FROM element for the target (the elements of the collection). FromElement destination = CreateAndAddFromElement( associatedEntityName, _classAlias, targetEntityPersister, (EntityType)queryableCollection.ElementType, tableAlias ); // If the join is implied, then don't include sub-classes on the element. if (_implied) { destination.IncludeSubclasses = false; } _fromClause.AddCollectionJoinFromElementByPath(_path, destination); // origin.addDestination(destination); // Add the query spaces. _fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); CollectionType type = queryableCollection.CollectionType; string role = type.Role; string roleAlias = _origin.TableAlias; string[] targetColumns = sfh.GetCollectionElementColumns(role, roleAlias); IAssociationType elementAssociationType = sfh.GetElementAssociationType(type); // Create the join element under the from element. JoinSequence joinSequence = sfh.CreateJoinSequence(_implied, elementAssociationType, tableAlias, JoinType.InnerJoin, targetColumns); FromElement elem = InitializeJoin(_path, destination, joinSequence, targetColumns, _origin, false); elem.UseFromFragment = true; // The associated entity is implied, but it must be included in the FROM. elem.CollectionTableAlias = roleAlias; // The collection alias is the role. return(elem); }
private static SqlString ProcessFromFragment(SqlString frag, JoinSequence join) { SqlString fromFragment = frag.Trim(); // The FROM fragment will probably begin with ', '. Remove this if it is present. if (fromFragment.StartsWithCaseInsensitive(", ")) { fromFragment = fromFragment.Substring(2); } return(fromFragment); }
private void AddJoin(JoinSequence joinSequence, QueryTranslator q) { q.AddFromJoinOnly(pathExpressionParser.Name, joinSequence); try { AddToCurrentJoin(joinSequence.ToJoinFragment(q.EnabledFilters, true).ToWhereFragmentString); } catch (MappingException me) { throw new QueryException(me); } }
/// <summary> /// Create a join sequence rooted at the given collection. /// </summary> /// <param name="collPersister">The persister for the collection at which the join should be rooted.</param> /// <param name="collectionName">The alias to use for qualifying column references.</param> /// <returns>The generated join sequence.</returns> public JoinSequence CreateCollectionJoinSequence(IQueryableCollection collPersister, String collectionName) { JoinSequence joinSequence = CreateJoinSequence(); joinSequence.SetRoot(collPersister, collectionName); joinSequence.SetUseThetaStyle(true); // TODO: figure out how this should be set. /////////////////////////////////////////////////////////////////////////////// // This was the reason for failures regarding INDEX_OP and subclass joins on // theta-join dialects; not sure what behaviour we were trying to emulate ;) // joinSequence = joinSequence.getFromPart(); // Emulate the old addFromOnly behavior. return joinSequence; }
IASTNode CreateFromFilterElement(IASTNode filterEntity, IASTNode alias) { var fromElementFound = true; var fromElement = _currentFromClause.GetFromElement(alias.Text) ?? _currentFromClause.GetFromElementByClassName(filterEntity.Text); if (fromElement == null) { fromElementFound = false; fromElement = _currentFromClause.AddFromElement(filterEntity.Text, alias); } FromClause fromClause = fromElement.FromClause; IQueryableCollection persister = _sessionFactoryHelper.GetCollectionPersister(_collectionFilterRole); // Get the names of the columns used to link between the collection // owner and the collection elements. String[] keyColumnNames = persister.KeyColumnNames; String fkTableAlias = persister.IsOneToMany ? fromElement.TableAlias : fromClause.AliasGenerator.CreateName(_collectionFilterRole); JoinSequence join = _sessionFactoryHelper.CreateJoinSequence(); join.SetRoot(persister, fkTableAlias); if (!persister.IsOneToMany) { join.AddJoin((IAssociationType)persister.ElementType, fromElement.TableAlias, JoinType.InnerJoin, persister.GetElementColumnNames(fkTableAlias)); } join.AddCondition(fkTableAlias, keyColumnNames, " = ", true); fromElement.JoinSequence = join; fromElement.Filter = true; if (log.IsDebugEnabled()) { log.Debug("createFromFilterElement() : processed filter FROM element."); } if (fromElementFound) { return((IASTNode)adaptor.Nil()); } return(fromElement); }
public FromElement CreateEntityJoin( string entityClass, string tableAlias, JoinSequence joinSequence, bool fetchFlag, bool inFrom, EntityType type) { FromElement elem = CreateJoin(entityClass, tableAlias, joinSequence, type, false); elem.Fetch = fetchFlag; //if (numberOfTables > 1 && _implied && !elem.UseFromFragment) // NH Different behavior: numberOfTables was removed because an // implicit join is an implicit join even if it not come from a // multi-table entity if (_implied && !elem.UseFromFragment) { if (Log.IsDebugEnabled) { Log.Debug("createEntityJoin() : Implied entity join"); } elem.UseFromFragment = true; } // If this is an implied join in a FROM clause, then use ANSI-style joining, and set the // flag on the FromElement that indicates that it was implied in the FROM clause itself. if (_implied && inFrom) { joinSequence.SetUseThetaStyle(false); elem.UseFromFragment = true; elem.SetImpliedInFromClause(true); } if (elem.Walker.IsSubQuery) { // two conditions where we need to transform this to a theta-join syntax: // 1) 'elem' is the "root from-element" in correlated subqueries // 2) The DotNode.useThetaStyleImplicitJoins has been set to true // and 'elem' represents an implicit join if (elem.FromClause != elem.Origin.FromClause || DotNode.UseThetaStyleImplicitJoins) { // the "root from-element" in correlated subqueries do need this piece elem.Type = HqlSqlWalker.FROM_FRAGMENT; joinSequence.SetUseThetaStyle(true); elem.UseFromFragment = false; } } return(elem); }
private FromElement InitializeJoin( string path, FromElement destination, JoinSequence joinSequence, string[] columns, FromElement origin, bool manyToMany) { destination.Type = HqlSqlWalker.JOIN_FRAGMENT; destination.JoinSequence = joinSequence; destination.Columns = columns; destination.SetOrigin(origin, manyToMany); _fromClause.AddJoinByPathMap(path, destination); return(destination); }
public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, JoinType joinType, string alias) : base(new CommonToken(HqlSqlWalker.ENTITY_JOIN, entityPersister.TableName)) { string tableAlias = fromClause.AliasGenerator.CreateName(entityPersister.EntityName); EntityType entityType = (EntityType)entityPersister.Type; InitializeEntity(fromClause, entityPersister.EntityName, entityPersister, entityType, alias, tableAlias); //NH Specific: hibernate uses special class EntityJoinJoinSequenceImpl JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) .AddJoin(entityType, tableAlias, joinType, Array.Empty <string>()); fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); }
private FromElement CreateJoin( string entityClass, string tableAlias, JoinSequence joinSequence, EntityType type, bool manyToMany) { // origin, path, implied, columns, classAlias, IEntityPersister entityPersister = _fromClause.SessionFactoryHelper.RequireClassPersister(entityClass); FromElement destination = CreateAndAddFromElement(entityClass, _classAlias, entityPersister, type, tableAlias); return(InitializeJoin(_path, destination, joinSequence, Columns, _origin, manyToMany)); }
private void AddJoinNodes(QueryNode query, JoinSequence join, FromElement fromElement) { JoinFragment joinFragment = join.ToJoinFragment( _walker.EnabledFilters, fromElement.UseFromFragment || fromElement.IsDereferencedBySuperclassOrSubclassProperty, fromElement.WithClauseFragment, fromElement.WithClauseJoinAlias ); SqlString frag = joinFragment.ToFromFragmentString; SqlString whereFrag = joinFragment.ToWhereFragmentString; // If the from element represents a JOIN_FRAGMENT and it is // a theta-style join, convert its type from JOIN_FRAGMENT // to FROM_FRAGMENT if (fromElement.Type == HqlSqlWalker.JOIN_FRAGMENT && (join.IsThetaStyle || StringHelper.IsNotEmpty(whereFrag))) { fromElement.Type = HqlSqlWalker.FROM_FRAGMENT; fromElement.JoinSequence.SetUseThetaStyle(true); // this is used during SqlGenerator processing } // If there is a FROM fragment and the FROM element is an explicit, then add the from part. if (fromElement.UseFromFragment /*&& StringHelper.isNotEmpty( frag )*/) { SqlString fromFragment = ProcessFromFragment(frag, join).Trim(); if (log.IsDebugEnabled) { log.Debug("Using FROM fragment [" + fromFragment + "]"); } ProcessDynamicFilterParameters( fromFragment, fromElement, _walker ); } _syntheticAndFactory.AddWhereFragment( joinFragment, whereFrag, query, fromElement, _walker ); }
public void ProcessJoins(IRestrictableStatement query) { FromClause fromClause = query.FromClause; var supportRootAlias = !(query is DeleteStatement || query is UpdateStatement); IList <FromElement> fromElements; if (DotNode.UseThetaStyleImplicitJoins) { // for regression testing against output from the old parser... // found it easiest to simply reorder the FromElements here into ascending order // in terms of injecting them into the resulting sql ast in orders relative to those // expected by the old parser; this is definitely another of those "only needed // for regression purposes". The SyntheticAndFactory, then, simply injects them as it // encounters them. fromElements = new List <FromElement>(); var t = fromClause.GetFromElementsTyped(); for (int i = t.Count - 1; i >= 0; i--) { fromElements.Add(t[i]); } } else { fromElements = fromClause.GetFromElementsTyped(); } // Iterate through the alias,JoinSequence pairs and generate SQL token nodes. foreach (FromElement fromElement in fromElements) { JoinSequence join = fromElement.JoinSequence; join.SetSelector(new JoinSequenceSelector(_walker, fromClause, fromElement)); // the delete and update statements created here will never be executed when IsMultiTable is true, // only the where clause will be used by MultiTableUpdateExecutor/MultiTableDeleteExecutor. In that case // we have to use the alias from the persister. AddJoinNodes(query, join, fromElement, supportRootAlias || fromElement.Queryable.IsMultiTable); } }
public static string CreateCollectionSubquery( JoinSequence joinSequence, IDictionary <string, IFilter> enabledFilters, String[] columns) { try { JoinFragment join = joinSequence.ToJoinFragment(enabledFilters, true); return(new StringBuilder() .Append("select ") .Append(StringHelper.Join(", ", columns)) .Append(" from ") .Append(join.ToFromFragmentString.Substring(2)) // remove initial ", " .Append(" where ") .Append(join.ToWhereFragmentString.Substring(5)) // remove initial " and " .ToString()); } catch (MappingException me) { throw new QueryException(me); } }
private void PrepareForIndex(QueryTranslator q) { IQueryableCollection collPersister = q.GetCollectionPersister(collectionRole); if (!collPersister.HasIndex) { throw new QueryException("unindexed collection before []"); } string[] indexCols = collPersister.IndexColumnNames; if (indexCols.Length != 1) { throw new QueryException("composite-index appears in []: " + path); } JoinSequence fromJoins = new JoinSequence(q.Factory) .SetUseThetaStyle(useThetaStyleJoin) .SetRoot(collPersister, collectionName) .SetNext(joinSequence.Copy()); if (!continuation) { AddJoin(collectionName, collPersister.CollectionType); } joinSequence.AddCondition(new SqlString(collectionName + '.' + indexCols[0] + " = ")); CollectionElement elem = new CollectionElement(); elem.ElementColumns = collPersister.GetElementColumnNames(collectionName); elem.Type = collPersister.ElementType; elem.IsOneToMany = collPersister.IsOneToMany; elem.Alias = collectionName; elem.JoinSequence = joinSequence; collectionElements.Add(elem); //addlast SetExpectingCollectionIndex(); q.AddCollection(collectionName, collectionRole); q.AddJoin(collectionName, fromJoins); }
public void ProcessJoins(QueryNode query) { FromClause fromClause = query.FromClause; IList <IASTNode> fromElements; if (DotNode.UseThetaStyleImplicitJoins) { // for regression testing against output from the old parser... // found it easiest to simply reorder the FromElements here into ascending order // in terms of injecting them into the resulting sql ast in orders relative to those // expected by the old parser; this is definitely another of those "only needed // for regression purposes". The SyntheticAndFactory, then, simply injects them as it // encounters them. fromElements = new List <IASTNode>(); IList <IASTNode> t = fromClause.GetFromElements(); for (int i = t.Count - 1; i >= 0; i--) { fromElements.Add(t[i]); } } else { fromElements = fromClause.GetFromElements(); } // Iterate through the alias,JoinSequence pairs and generate SQL token nodes. foreach (FromElement fromElement in fromElements) { JoinSequence join = fromElement.JoinSequence; join.SetSelector(new JoinSequenceSelector(_walker, fromClause, fromElement)); AddJoinNodes(query, join, fromElement); } }
public override void Resolve(bool generateJoin, bool implicitJoin, string classAlias, IASTNode parent) { if (IsResolved) { return; } FromReferenceNode collectionNode = ( FromReferenceNode )GetChild(0); SessionFactoryHelperExtensions sessionFactoryHelper = SessionFactoryHelper; collectionNode.ResolveIndex(this); // Fully resolve the map reference, create implicit joins. IType type = collectionNode.DataType; if (!type.IsCollectionType) { throw new SemanticException("The [] operator cannot be applied to type " + type); } string collectionRole = (( CollectionType )type).Role; IQueryableCollection queryableCollection = sessionFactoryHelper.RequireQueryableCollection(collectionRole); if (!queryableCollection.HasIndex) { throw new QueryException("unindexed fromElement before []: " + collectionNode.Path); } // Generate the inner join -- The elements need to be joined to the collection they are in. FromElement fromElement = collectionNode.FromElement; String elementTable = fromElement.TableAlias; FromClause fromClause = fromElement.FromClause; String path = collectionNode.Path; FromElement elem = fromClause.FindCollectionJoin(path); if (elem == null) { FromElementFactory factory = new FromElementFactory(fromClause, fromElement, path); elem = factory.CreateCollectionElementsJoin(queryableCollection, elementTable); if (Log.IsDebugEnabled) { Log.Debug("No FROM element found for the elements of collection join path " + path + ", created " + elem); } } else { if (Log.IsDebugEnabled) { Log.Debug("FROM element found for collection join path " + path); } } // The 'from element' that represents the elements of the collection. FromElement = fromElement; // Add the condition to the join sequence that qualifies the indexed element. IASTNode selector = GetChild(1); if (selector == null) { throw new QueryException("No index value!"); } // Sometimes use the element table alias, sometimes use the... umm... collection table alias (many to many) String collectionTableAlias = elementTable; if (elem.CollectionTableAlias != null) { collectionTableAlias = elem.CollectionTableAlias; } // TODO: get SQL rendering out of here, create an AST for the join expressions. // Use the SQL generator grammar to generate the SQL text for the index expression. JoinSequence joinSequence = fromElement.JoinSequence; string[] indexCols = queryableCollection.IndexColumnNames; if (indexCols.Length != 1) { throw new QueryException("composite-index appears in []: " + collectionNode.Path); } SqlGenerator gen = new SqlGenerator(SessionFactoryHelper.Factory, new CommonTreeNodeStream(selector)); try { gen.simpleExpr(); //TODO: used to be exprNoParens! was this needed? } catch (RecognitionException e) { throw new QueryException(e.Message, e); } string selectorExpression = gen.GetSQL().ToString(); joinSequence.AddCondition(new SqlString(collectionTableAlias + '.' + indexCols[0] + " = " + selectorExpression)); //joinSequence.AddCondition(collectionTableAlias, new string[] { indexCols[0] }, selectorExpression, false); IList <IParameterSpecification> paramSpecs = gen.GetCollectedParameters(); if (paramSpecs != null) { switch (paramSpecs.Count) { case 0: // nothing to do break; case 1: IParameterSpecification paramSpec = paramSpecs[0]; paramSpec.ExpectedType = queryableCollection.IndexType; fromElement.SetIndexCollectionSelectorParamSpec(paramSpec); break; default: fromElement.SetIndexCollectionSelectorParamSpec( new AggregatedIndexCollectionSelectorParameterSpecifications(paramSpecs) ); break; } } // Now, set the text for this node. It should be the element columns. String[] elementColumns = queryableCollection.GetElementColumnNames(elementTable); Text = elementColumns[0]; IsResolved = true; }
public void Token(string token, QueryTranslator q) { if (token != null) { path.Append(token); } string alias = q.GetPathAlias(path.ToString()); if (alias != null) { Reset(q); //reset the dotcount (but not the path) currentName = alias; //after reset! currentPropertyMapping = q.GetPropertyMapping(currentName); if (!ignoreInitialJoin) { JoinSequence ojf = q.GetPathJoin(path.ToString()); try { joinSequence.AddCondition(ojf.ToJoinFragment(q.EnabledFilters, true).ToWhereFragmentString); //after reset! } catch (MappingException me) { throw new QueryException(me); } // we don't need to worry about any condition in the ON clause // here (toFromFragmentString), since anything in the ON condition // is already applied to the whole query } } else if (".".Equals(token)) { dotcount++; } else { if (dotcount == 0) { if (!continuation) { if (!q.IsName(token)) { throw new QueryException("undefined alias or unknown mapping: " + token); } currentName = token; currentPropertyMapping = q.GetPropertyMapping(currentName); } } else if (dotcount == 1) { if (currentName != null) { currentProperty = token; } else if (collectionName != null) { //IQueryableCollection p = q.GetCollectionPersister( collectionRole ); //DoCollectionProperty( token, p, collectionName ); continuation = false; } else { throw new QueryException("unexpected"); } } else { // dotcount>=2 // Do the corresponding RHS IType propertyType = PropertyType; if (propertyType == null) { throw new QueryException("unresolved property: " + currentProperty); } if (propertyType.IsComponentType) { DereferenceComponent(token); } else if (propertyType.IsEntityType) { DereferenceEntity(token, (EntityType)propertyType, q); } else if (propertyType.IsCollectionType) { DereferenceCollection(token, ((CollectionType)propertyType).Role, q); } else if (token != null) { throw new QueryException("dereferenced: " + currentProperty); } } } }
public FromElement CreateCollection(IQueryableCollection queryableCollection, string role, JoinType joinType, bool fetchFlag, bool indexed) { if (!_collection) { throw new InvalidOperationException("FromElementFactory not initialized for collections!"); } _inElementsFunction = indexed; FromElement elem; _queryableCollection = queryableCollection; _collectionType = queryableCollection.CollectionType; string roleAlias = _fromClause.AliasGenerator.CreateName(role); // Correlated subqueries create 'special' implied from nodes // because correlated subselects can't use an ANSI-style join bool explicitSubqueryFromElement = _fromClause.IsSubQuery && !_implied; if (explicitSubqueryFromElement) { string pathRoot = StringHelper.Root(_path); FromElement origin = _fromClause.GetFromElement(pathRoot); if (origin == null || origin.FromClause != _fromClause) { _implied = true; } } // super-duper-classic-parser-regression-testing-mojo-magic... if (explicitSubqueryFromElement && DotNode.UseThetaStyleImplicitJoins) { _implied = true; } IType elementType = queryableCollection.ElementType; if (elementType.IsEntityType) { // A collection of entities... elem = CreateEntityAssociation(role, roleAlias, joinType); } else if (elementType.IsComponentType) { // A collection of components... JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); elem = CreateCollectionJoin(joinSequence, roleAlias); } else { // A collection of scalar elements... JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); elem = CreateCollectionJoin(joinSequence, roleAlias); } elem.SetRole(role); elem.QueryableCollection = queryableCollection; // Don't include sub-classes for implied collection joins or subquery joins. if (_implied) { elem.IncludeSubclasses = false; } if (explicitSubqueryFromElement) { elem.InProjectionList = true; // Treat explict from elements in sub-queries properly. } if (fetchFlag) { elem.Fetch = true; } return(elem); }
private void DereferenceEntityJoin(string classAlias, EntityType propertyType, bool impliedJoin, IASTNode parent) { _dereferenceType = DerefEntity; if (Log.IsDebugEnabled) { Log.Debug("dereferenceEntityJoin() : generating join for " + _propertyName + " in " + FromElement.ClassName + " " + ((classAlias == null) ? "{no alias}" : "(" + classAlias + ")") + " parent = " + ASTUtil.GetDebugstring(parent) ); } // Create a new FROM node for the referenced class. string associatedEntityName = propertyType.GetAssociatedEntityName(); string tableAlias = AliasGenerator.CreateName(associatedEntityName); string[] joinColumns = GetColumns(); string joinPath = Path; if (impliedJoin && Walker.IsInFrom) { _joinType = Walker.ImpliedJoinType; } FromClause currentFromClause = Walker.CurrentFromClause; FromElement elem = currentFromClause.FindJoinByPath(joinPath); /////////////////////////////////////////////////////////////////////////////// // // This is the piece which recognizes the condition where an implicit join path // resolved earlier in a correlated subquery is now being referenced in the // outer query. For 3.0final, we just let this generate a second join (which // is exactly how the old parser handles this). Eventually we need to add this // logic back in and complete the logic in FromClause.promoteJoin; however, // FromClause.promoteJoin has its own difficulties (see the comments in // FromClause.promoteJoin). // // if ( elem == null ) { // // see if this joinPath has been used in a "child" FromClause, and if so // // promote that element to the outer query // FromClause currentNodeOwner = getFromElement().getFromClause(); // FromClause currentJoinOwner = currentNodeOwner.locateChildFromClauseWithJoinByPath( joinPath ); // if ( currentJoinOwner != null && currentNodeOwner != currentJoinOwner ) { // elem = currentJoinOwner.findJoinByPathLocal( joinPath ); // if ( elem != null ) { // currentFromClause.promoteJoin( elem ); // // EARLY EXIT!!! // return; // } // } // } // /////////////////////////////////////////////////////////////////////////////// bool found = elem != null; // even though we might find a pre-existing element by join path, for FromElements originating in a from-clause // we should only ever use the found element if the aliases match (null != null here). Implied joins are // always (?) ok to reuse. bool useFoundFromElement = found && (elem.IsImplied || (AreSame(classAlias, elem.ClassAlias))); if (!useFoundFromElement) { // If this is an implied join in a from element, then use the impled join type which is part of the // tree parser's state (set by the gramamar actions). JoinSequence joinSequence = SessionFactoryHelper .CreateJoinSequence(impliedJoin, propertyType, tableAlias, _joinType, joinColumns); FromElementFactory factory = new FromElementFactory( currentFromClause, GetLhs().FromElement, joinPath, classAlias, joinColumns, impliedJoin ); elem = factory.CreateEntityJoin( associatedEntityName, tableAlias, joinSequence, _fetch, Walker.IsInFrom, propertyType ); } else { currentFromClause.AddDuplicateAlias(classAlias, elem); } SetImpliedJoin(elem); Walker.AddQuerySpaces(elem.EntityPersister.QuerySpaces); FromElement = elem; // This 'dot' expression now refers to the resulting from element. }
public void ProcessJoins(IRestrictableStatement query) { FromClause fromClause = query.FromClause; IList <FromElement> fromElements; if (DotNode.UseThetaStyleImplicitJoins) { // for regression testing against output from the old parser... // found it easiest to simply reorder the FromElements here into ascending order // in terms of injecting them into the resulting sql ast in orders relative to those // expected by the old parser; this is definitely another of those "only needed // for regression purposes". The SyntheticAndFactory, then, simply injects them as it // encounters them. fromElements = new List <FromElement>(); var t = fromClause.GetFromElementsTyped(); for (int i = t.Count - 1; i >= 0; i--) { fromElements.Add(t[i]); } } else { fromElements = fromClause.GetFromElementsTyped(); for (var index = fromElements.Count - 1; index >= 0; index--) { var fromElement = fromElements[index]; // We found an implied from element that is used in the WITH clause of another from element, so it need to become part of it's join sequence if (fromElement.IsImplied && fromElement.IsPartOfJoinSequence == null) { var origin = fromElement.Origin; while (origin.IsImplied) { origin = origin.Origin; origin.IsPartOfJoinSequence = false; } if (origin.WithClauseFragment?.Contains(fromElement.TableAlias + ".") == true) { List <FromElement> elements = new List <FromElement>(); while (fromElement.IsImplied) { elements.Add(fromElement); // This from element will be rendered as part of the origins join sequence fromElement.Text = string.Empty; fromElement.IsPartOfJoinSequence = true; fromElement = fromElement.Origin; } for (var i = elements.Count - 1; i >= 0; i--) { origin.JoinSequence.AddJoin(elements[i]); } } } } } // Iterate through the alias,JoinSequence pairs and generate SQL token nodes. foreach (FromElement fromElement in fromElements) { if (fromElement.IsPartOfJoinSequence == true) { continue; } JoinSequence join = fromElement.JoinSequence; join.SetSelector(new JoinSequenceSelector(_walker, fromClause, fromElement)); // the delete and update statements created here will never be executed when IsMultiTable is true, // only the where clause will be used by MultiTableUpdateExecutor/MultiTableDeleteExecutor. In that case // we have to use the alias from the persister. AddJoinNodes(query, join, fromElement); } }