private FromElement createManyToMany( String role, String associatedEntityName, String roleAlias, Queryable entityPersister, EntityType type, JoinType joinType) throws SemanticException { FromElement elem; SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper(); 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.getAliasGenerator().createName(entityPersister.getEntityName()); 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.setUseFromFragment(true); } return elem; }
private void addJoinNodes(QueryNode query, JoinSequence join, FromElement fromElement) { JoinFragment joinFragment = join.toJoinFragment( walker.getEnabledFilters(), fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(), fromElement.getWithClauseFragment(), fromElement.getWithClauseJoinAlias()); String frag = joinFragment.toFromFragmentString(); String 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.getType() == JOIN_FRAGMENT && (join.isThetaStyle() || StringHelper.isNotEmpty(whereFrag))) { fromElement.setType(FROM_FRAGMENT); fromElement .getJoinSequence() .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 )*/) { String fromFragment = processFromFragment(frag, join).trim(); LOG.debugf("Using FROM fragment [%s]", fromFragment); processDynamicFilterParameters(fromFragment, fromElement, walker); } syntheticAndFactory.addWhereFragment(joinFragment, whereFrag, query, fromElement, walker); }
private void prepareForIndex(QueryTranslatorImpl q) throws QueryException { QueryableCollection collPersister = q.getCollectionPersister(collectionRole); if (!collPersister.hasIndex()) throw new QueryException("unindexed collection before []: " + path); String[] indexCols = collPersister.getIndexColumnNames(); if (indexCols.length != 1) throw new QueryException("composite-index appears in []: " + path); // String[] keyCols = collPersister.getKeyColumnNames(); JoinSequence fromJoins = new JoinSequence(q.getFactory()) .setUseThetaStyle(useThetaStyleJoin) .setRoot(collPersister, collectionName) .setNext(joinSequence.copy()); if (!continuation) addJoin(collectionName, collPersister.getCollectionType()); joinSequence.addCondition( collectionName + '.' + indexCols[0] + " = "); // TODO: get SQL rendering out of here CollectionElement elem = new CollectionElement(); elem.elementColumns = collPersister.getElementColumnNames(collectionName); elem.elementType = collPersister.getElementType(); elem.isOneToMany = collPersister.isOneToMany(); elem.alias = collectionName; elem.joinSequence = joinSequence; collectionElements.addLast(elem); setExpectingCollectionIndex(); q.addCollection(collectionName, collectionRole); q.addFromJoinOnly(collectionName, fromJoins); }
public void processJoins(QueryNode query) { final FromClause fromClause = query.getFromClause(); final List 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 ArrayList(); ListIterator liter = fromClause.getFromElements().listIterator(fromClause.getFromElements().size()); while (liter.hasPrevious()) { fromElements.add(liter.previous()); } } else { fromElements = fromClause.getFromElements(); } // Iterate through the alias,JoinSequence pairs and generate SQL token nodes. Iterator iter = fromElements.iterator(); while (iter.hasNext()) { final FromElement fromElement = (FromElement) iter.next(); JoinSequence join = fromElement.getJoinSequence(); join.setSelector( new JoinSequence.Selector() { public boolean includeSubclasses(String alias) { // The uber-rule here is that we need to include subclass joins if // the FromElement is in any way dereferenced by a property from // the subclass table; otherwise we end up with column references // qualified by a non-existent table reference in the resulting SQL... boolean containsTableAlias = fromClause.containsTableAlias(alias); if (fromElement.isDereferencedBySubclassProperty()) { // TODO : or should we return 'containsTableAlias'?? LOG.trace( "Forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]"); return true; } boolean shallowQuery = walker.isShallowQuery(); boolean includeSubclasses = fromElement.isIncludeSubclasses(); boolean subQuery = fromClause.isSubQuery(); return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery; } }); addJoinNodes(query, join, fromElement); } }
public FromElement createEntityJoin( String entityClass, String tableAlias, JoinSequence joinSequence, boolean fetchFlag, boolean inFrom, EntityType type, String role, String joinPath) throws SemanticException { FromElement elem = createJoin(entityClass, tableAlias, joinSequence, type, false); elem.setFetch(fetchFlag); if (joinPath != null) { elem.applyTreatAsDeclarations(fromClause.getWalker().getTreatAsDeclarationsByPath(joinPath)); } EntityPersister entityPersister = elem.getEntityPersister(); int numberOfTables = entityPersister.getQuerySpaces().length; if (numberOfTables > 1 && implied && !elem.useFromFragment()) { LOG.debug("createEntityJoin() : Implied multi-table entity join"); elem.setUseFromFragment(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.setUseFromFragment(true); elem.setImpliedInFromClause(true); } if (elem.getWalker().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.getFromClause() != elem.getOrigin().getFromClause() || // ( implied && DotNode.useThetaStyleImplicitJoins ) ) { PathSeparatorNode.useThetaStyleImplicitJoins) { // the "root from-element" in correlated subqueries do need this piece elem.setType(FROM_FRAGMENT); joinSequence.setUseThetaStyle(true); elem.setUseFromFragment(false); } } elem.setRole(role); return elem; }
private void addJoin(String name, AssociationType joinableType) throws QueryException { try { joinSequence.addJoin(joinableType, name, joinType, currentColumns()); } catch (MappingException me) { throw new QueryException(me); } }
private void addJoin(String name, AssociationType joinableType, String[] foreignKeyColumns) throws QueryException { try { joinSequence.addJoin(joinableType, name, joinType, foreignKeyColumns); } catch (MappingException me) { throw new QueryException(me); } }
private void addJoin(JoinSequence joinSequence, QueryTranslatorImpl q) throws QueryException { // JoinFragment fromClause = q.createJoinFragment(true); // fromClause.addJoins( join.toJoinFragment().toFromFragmentString(), StringHelper.EMPTY_STRING // ); q.addFromJoinOnly(pathExpressionParser.getName(), joinSequence); try { addToCurrentJoin( joinSequence.toJoinFragment(q.getEnabledFilters(), true).toWhereFragmentString()); } catch (MappingException me) { throw new QueryException(me); } }
/** Used for collection filters */ private void addFromAssociation(final String elementName, final String collectionRole) throws QueryException { // q.addCollection(collectionName, collectionRole); QueryableCollection persister = getCollectionPersister(collectionRole); Type collectionElementType = persister.getElementType(); if (!collectionElementType.isEntityType()) { throw new QueryException("collection of values in filter: " + elementName); } String[] keyColumnNames = persister.getKeyColumnNames(); // if (keyColumnNames.length!=1) throw new QueryException("composite-key collection in filter: " // + collectionRole); String collectionName; JoinSequence join = new JoinSequence(getFactory()); collectionName = persister.isOneToMany() ? elementName : createNameForCollection(collectionRole); join.setRoot(persister, collectionName); if (!persister.isOneToMany()) { // many-to-many addCollection(collectionName, collectionRole); try { join.addJoin( (AssociationType) persister.getElementType(), elementName, JoinType.INNER_JOIN, persister.getElementColumnNames(collectionName)); } catch (MappingException me) { throw new QueryException(me); } } join.addCondition(collectionName, keyColumnNames, " = ?"); // if ( persister.hasWhere() ) join.addCondition( persister.getSQLWhereString(collectionName) ); EntityType elemType = (EntityType) collectionElementType; addFrom(elementName, elemType.getAssociatedEntityName(), join); }
private void mergeJoins(JoinFragment ojf) throws MappingException, QueryException { Iterator iter = joins.entrySet().iterator(); while (iter.hasNext()) { Map.Entry me = (Map.Entry) iter.next(); String name = (String) me.getKey(); JoinSequence join = (JoinSequence) me.getValue(); join.setSelector( new JoinSequence.Selector() { public boolean includeSubclasses(String alias) { boolean include = returnedTypes.contains(alias) && !isShallowQuery(); return include; } }); if (typeMap.containsKey(name)) { ojf.addFragment(join.toJoinFragment(enabledFilters, true)); } else if (collections.containsKey(name)) { ojf.addFragment(join.toJoinFragment(enabledFilters, true)); } else { // name from a super query (a bit inelegant that it shows up here) } } }
public static String createCollectionSubquery( JoinSequence joinSequence, Map enabledFilters, String[] columns) { try { JoinFragment join = joinSequence.toJoinFragment(enabledFilters, true); return new StringBuilder("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 dereferenceEntity( String propertyName, EntityType propertyType, QueryTranslatorImpl q) throws QueryException { // NOTE: we avoid joining to the next table if the named property is just the foreign key value // if its "id" boolean isIdShortcut = EntityPersister.ENTITY_ID.equals(propertyName) && propertyType.isReferenceToPrimaryKey(); // or its the id property name final String idPropertyName; try { idPropertyName = propertyType.getIdentifierOrUniqueKeyPropertyName(q.getFactory()); } catch (MappingException me) { throw new QueryException(me); } boolean isNamedIdPropertyShortcut = idPropertyName != null && idPropertyName.equals(propertyName) && propertyType.isReferenceToPrimaryKey(); if (isIdShortcut || isNamedIdPropertyShortcut) { // special shortcut for id properties, skip the join! // this must only occur at the _end_ of a path expression if (componentPath.length() > 0) componentPath.append('.'); componentPath.append(propertyName); } else { String entityClass = propertyType.getAssociatedEntityName(); String name = q.createNameFor(entityClass); q.addType(name, entityClass); addJoin(name, propertyType); if (propertyType.isOneToOne()) oneToOneOwnerName = currentName; ownerAssociationType = propertyType; currentName = name; currentProperty = propertyName; q.addPathAliasAndJoin( path.substring(0, path.toString().lastIndexOf('.')), name, joinSequence.copy()); componentPath.setLength(0); currentPropertyMapping = q.getEntityPersister(entityClass); } }
void addFromJoinOnly(String name, JoinSequence joinSequence) throws QueryException { addJoin(name, joinSequence.getFromPart()); }
public void token(String token, QueryTranslatorImpl q) throws QueryException { 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.getEnabledFilters(), 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: " + token); currentName = token; currentPropertyMapping = q.getPropertyMapping(currentName); } } else if (dotcount == 1) { if (currentName != null) { currentProperty = token; } else if (collectionName != null) { // processCollectionProperty(token, q.getCollectionPersister(collectionRole), // collectionName); continuation = false; } else { throw new QueryException("unexpected"); } } else { // dotcount>=2 // Do the corresponding RHS Type propertyType = getPropertyType(); if (propertyType == null) { throw new QueryException("unresolved property: " + path); } if (propertyType.isComponentType()) { dereferenceComponent(token); } else if (propertyType.isEntityType()) { if (!isCollectionValued()) dereferenceEntity(token, (EntityType) propertyType, q); } else if (propertyType.isCollectionType()) { dereferenceCollection(token, ((CollectionType) propertyType).getRole(), q); } else { if (token != null) throw new QueryException("dereferenced: " + path); } } } }