private FromElement createCollectionJoin(JoinSequence collectionJoinSequence, String tableAlias) throws SemanticException { String text = queryableCollection.getTableName(); AST ast = createFromElement(text); FromElement destination = (FromElement) ast; Type elementType = queryableCollection.getElementType(); if (elementType.isCollectionType()) { throw new SemanticException("Collections of collections are not supported!"); } destination.initializeCollection(fromClause, classAlias, tableAlias); destination.setType(JOIN_FRAGMENT); // Tag this node as a JOIN. destination.setIncludeSubclasses(false); // Don't include subclasses in the join. destination.setCollectionJoin(true); // This is a clollection join. destination.setJoinSequence(collectionJoinSequence); destination.setOrigin(origin, false); destination.setCollectionTableAlias(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.setText(""); // The destination node will have all the FROM text. origin.setCollectionJoin( true); // The parent node is a collection join too (voodoo - see JoinProcessor) fromClause.addCollectionJoinFromElementByPath(path, destination); fromClause.getWalker().addQuerySpaces(queryableCollection.getCollectionSpaces()); return destination; }
public void resolveCollectionProperty(AST expr) throws SemanticException { String propertyName = CollectionProperties.getNormalizedPropertyName(getMethodName()); if (expr instanceof FromReferenceNode) { FromReferenceNode collectionNode = (FromReferenceNode) expr; // If this is 'elements' then create a new FROM element. if (CollectionPropertyNames.COLLECTION_ELEMENTS.equals(propertyName)) { handleElements(collectionNode, propertyName); } else { // Not elements(x) fromElement = collectionNode.getFromElement(); setDataType(fromElement.getPropertyType(propertyName, propertyName)); selectColumns = fromElement.toColumns(fromElement.getTableAlias(), propertyName, inSelect); } if (collectionNode instanceof DotNode) { prepareAnyImplicitJoins((DotNode) collectionNode); } if (!inSelect) { fromElement.setText(""); fromElement.setUseWhereFragment(false); } prepareSelectColumns(selectColumns); setText(selectColumns[0]); setType(SqlTokenTypes.SQL_TOKEN); } else { throw new SemanticException( "Unexpected expression " + expr + " found for collection function " + propertyName); } }
private FromElement createManyToMany( String role, String associatedEntityName, String roleAlias, Queryable entityPersister, EntityType type, int 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 boolean isReturnableEntity(SelectExpression selectExpression) throws SemanticException { FromElement fromElement = selectExpression.getFromElement(); boolean isFetchOrValueCollection = fromElement != null && (fromElement.isFetch() || fromElement.isCollectionOfValuesOrComponents()); if (isFetchOrValueCollection) { return false; } else { return selectExpression.isReturnableEntity(); } }
/** * Prepares a derived (i.e., not explicitly defined in the query) select clause. * * @param fromClause The from clause to which this select clause is linked. */ public void initializeDerivedSelectClause(FromClause fromClause) throws SemanticException { if (prepared) { throw new IllegalStateException("SelectClause was already prepared!"); } // Used to be tested by the TCK but the test is no longer here // if ( getSessionFactoryHelper().isStrictJPAQLComplianceEnabled() && !getWalker().isSubQuery() // ) { // // NOTE : the isSubQuery() bit is a temporary hack... // throw new QuerySyntaxException( "JPA-QL compliance requires select clause" ); // } List fromElements = fromClause.getProjectionList(); ASTAppender appender = new ASTAppender(getASTFactory(), this); // Get ready to start adding nodes. int size = fromElements.size(); ArrayList queryReturnTypeList = new ArrayList(size); Iterator iterator = fromElements.iterator(); for (int k = 0; iterator.hasNext(); k++) { FromElement fromElement = (FromElement) iterator.next(); Type type = fromElement.getSelectType(); addCollectionFromElement(fromElement); if (type != null) { boolean collectionOfElements = fromElement.isCollectionOfValuesOrComponents(); if (!collectionOfElements) { if (!fromElement.isFetch()) { // Add the type to the list of returned sqlResultTypes. queryReturnTypeList.add(type); } fromElementsForLoad.add(fromElement); // Generate the select expression. String text = fromElement.renderIdentifierSelect(size, k); SelectExpressionImpl generatedExpr = (SelectExpressionImpl) appender.append(SqlTokenTypes.SELECT_EXPR, text, false); if (generatedExpr != null) { generatedExpr.setFromElement(fromElement); } } } } // Get all the select expressions (that we just generated) and render the select. SelectExpression[] selectExpressions = collectSelectExpressions(); if (getWalker().isShallowQuery()) { renderScalarSelects(selectExpressions, fromClause); } else { renderNonScalarSelects(selectExpressions, fromClause); } finishInitialization(queryReturnTypeList); }
private void prepareAnyImplicitJoins(DotNode dotNode) throws SemanticException { if (dotNode.getLhs() instanceof DotNode) { DotNode lhs = (DotNode) dotNode.getLhs(); FromElement lhsOrigin = lhs.getFromElement(); if (lhsOrigin != null && "".equals(lhsOrigin.getText())) { String lhsOriginText = lhsOrigin.getQueryable().getTableName() + " " + lhsOrigin.getTableAlias(); lhsOrigin.setText(lhsOriginText); } prepareAnyImplicitJoins(lhs); } }
void registerFromElement(FromElement element) { fromElements.add(element); String classAlias = element.getClassAlias(); if (classAlias != null) { // The HQL class alias refers to the class name. fromElementByClassAlias.put(classAlias, element); } // Associate the table alias with the element. String tableAlias = element.getTableAlias(); if (tableAlias != null) { fromElementByTableAlias.put(tableAlias, element); } }
private FromElement initializeJoin( String path, FromElement destination, JoinSequence joinSequence, String[] columns, FromElement origin, boolean manyToMany) { destination.setType(JOIN_FRAGMENT); destination.setJoinSequence(joinSequence); destination.setColumns(columns); destination.setOrigin(origin, manyToMany); fromClause.addJoinByPathMap(path, destination); return destination; }
private void typeDiscriminator(AST path) throws SemanticException { if (path == null) { throw new SemanticException("type() discriminator reference has no path!"); } FromReferenceNode pathAsFromReferenceNode = (FromReferenceNode) path; FromElement fromElement = pathAsFromReferenceNode.getFromElement(); TypeDiscriminatorMetadata typeDiscriminatorMetadata = fromElement.getTypeDiscriminatorMetadata(); setDataType(typeDiscriminatorMetadata.getResolutionType()); setText(typeDiscriminatorMetadata.getSqlFragment()); setType(SqlTokenTypes.SQL_TOKEN); }
FromElement createCollection( QueryableCollection queryableCollection, String role, int joinType, boolean fetchFlag, boolean indexed) throws SemanticException { if (!collection) { throw new IllegalStateException("FromElementFactory not initialized for collections!"); } this.inElementsFunction = indexed; FromElement elem; this.queryableCollection = queryableCollection; collectionType = queryableCollection.getCollectionType(); String roleAlias = fromClause.getAliasGenerator().createName(role); // Correlated subqueries create 'special' implied from nodes // because correlated subselects can't use an ANSI-style join boolean explicitSubqueryFromElement = fromClause.isSubQuery() && !implied; if (explicitSubqueryFromElement) { String pathRoot = StringHelper.root(path); FromElement origin = fromClause.getFromElement(pathRoot); if (origin == null || origin.getFromClause() != fromClause) { implied = true; } } // super-duper-classic-parser-regression-testing-mojo-magic... if (explicitSubqueryFromElement && DotNode.useThetaStyleImplicitJoins) { implied = true; } Type elementType = queryableCollection.getElementType(); 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.setQueryableCollection(queryableCollection); // Don't include sub-classes for implied collection joins or subquery joins. if (implied) { elem.setIncludeSubclasses(false); } if (explicitSubqueryFromElement) { elem.setInProjectionList(true); // Treat explict from elements in sub-queries properly. } if (fetchFlag) { elem.setFetch(true); } return elem; }
private void addCollectionFromElement(FromElement fromElement) { if (fromElement.isFetch()) { if (fromElement.getQueryableCollection() != null) { String suffix; if (collectionFromElements == null) { collectionFromElements = new ArrayList(); suffix = VERSION2_SQL ? "__" : "0__"; } else { suffix = Integer.toString(collectionFromElements.size()) + "__"; } collectionFromElements.add(fromElement); fromElement.setCollectionSuffix(suffix); } } }
private FromElement createEntityAssociation(String role, String roleAlias, int joinType) throws SemanticException { FromElement elem; Queryable entityPersister = (Queryable) queryableCollection.getElementPersister(); String associatedEntityName = entityPersister.getEntityName(); // 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.getElementType(), false); } else { if (log.isDebugEnabled()) { log.debug( "createManyToMany() : path = " + path + " role = " + role + " associatedEntityName = " + associatedEntityName); } elem = createManyToMany( role, associatedEntityName, roleAlias, entityPersister, (EntityType) queryableCollection.getElementType(), joinType); fromClause.getWalker().addQuerySpaces(queryableCollection.getCollectionSpaces()); } elem.setCollectionTableAlias(roleAlias); return elem; }
private void renderNonScalarIdentifiers( FromElement fromElement, int nonscalarSize, int j, SelectExpression expr, ASTAppender appender) { String text = fromElement.renderIdentifierSelect(nonscalarSize, j); if (!fromElement.getFromClause().isSubQuery()) { if (!scalarSelect && !getWalker().isShallowQuery()) { // TODO: is this a bit ugly? expr.setText(text); } else { appender.append(SqlTokenTypes.SQL_TOKEN, text, false); } } }
private void handleElements(FromReferenceNode collectionNode, String propertyName) { FromElement collectionFromElement = collectionNode.getFromElement(); QueryableCollection queryableCollection = collectionFromElement.getQueryableCollection(); String path = collectionNode.getPath() + "[]." + propertyName; log.debug("Creating elements for " + path); fromElement = collectionFromElement; if (!collectionFromElement.isCollectionOfValuesOrComponents()) { getWalker().addQuerySpaces(queryableCollection.getElementPersister().getQuerySpaces()); } setDataType(queryableCollection.getElementType()); selectColumns = collectionFromElement.toColumns(fromElement.getTableAlias(), propertyName, inSelect); }
public String getDisplayText() { return "{" + "method=" + getMethodName() + ",selectColumns=" + (selectColumns == null ? null : Arrays.asList(selectColumns)) + ",fromElement=" + fromElement.getTableAlias() + "}"; }
private FromElement createFromElementInSubselect( String path, String pathAlias, FromElement parentFromElement, String classAlias) throws SemanticException { if (log.isDebugEnabled()) { log.debug("createFromElementInSubselect() : path = " + path); } // Create an DotNode AST for the path and resolve it. FromElement fromElement = evaluateFromElementPath(path, classAlias); EntityPersister entityPersister = fromElement.getEntityPersister(); // If the first identifier in the path referrs to the class alias (not the class name), then // this // is a correlated subselect. If it's a correlated sub-select, use the existing table alias. // Otherwise // generate a new one. String tableAlias = null; boolean correlatedSubselect = pathAlias.equals(parentFromElement.getClassAlias()); if (correlatedSubselect) { tableAlias = fromElement.getTableAlias(); } else { tableAlias = null; } // If the from element isn't in the same clause, create a new from element. if (fromElement.getFromClause() != fromClause) { if (log.isDebugEnabled()) { log.debug("createFromElementInSubselect() : creating a new FROM element..."); } fromElement = createFromElement(entityPersister); initializeAndAddFromElement( fromElement, path, classAlias, entityPersister, (EntityType) ((Queryable) entityPersister).getType(), tableAlias); } if (log.isDebugEnabled()) { log.debug("createFromElementInSubselect() : " + path + " -> " + fromElement); } return fromElement; }
private void initializeAndAddFromElement( FromElement element, String className, String classAlias, EntityPersister entityPersister, EntityType type, String tableAlias) { if (tableAlias == null) { AliasGenerator aliasGenerator = fromClause.getAliasGenerator(); tableAlias = aliasGenerator.createName(entityPersister.getEntityName()); } element.initializeEntity(fromClause, className, entityPersister, type, classAlias, tableAlias); }
FromElement createElementJoin(QueryableCollection queryableCollection) throws SemanticException { FromElement elem; implied = true; // TODO: always true for now, but not if we later decide to support elements() in the // from clause inElementsFunction = true; Type elementType = queryableCollection.getElementType(); if (!elementType.isEntityType()) { throw new IllegalArgumentException( "Cannot create element join for a collection of non-entities!"); } this.queryableCollection = queryableCollection; SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper(); FromElement destination = null; String tableAlias = null; EntityPersister entityPersister = queryableCollection.getElementPersister(); tableAlias = fromClause.getAliasGenerator().createName(entityPersister.getEntityName()); String associatedEntityName = entityPersister.getEntityName(); EntityPersister targetEntityPersister = sfh.requireClassPersister(associatedEntityName); // Create the FROM element for the target (the elements of the collection). destination = createAndAddFromElement( associatedEntityName, classAlias, targetEntityPersister, (EntityType) queryableCollection.getElementType(), tableAlias); // If the join is implied, then don't include sub-classes on the element. if (implied) { destination.setIncludeSubclasses(false); } fromClause.addCollectionJoinFromElementByPath(path, destination); // origin.addDestination(destination); // Add the query spaces. fromClause.getWalker().addQuerySpaces(entityPersister.getQuerySpaces()); CollectionType type = queryableCollection.getCollectionType(); String role = type.getRole(); String roleAlias = origin.getTableAlias(); String[] targetColumns = sfh.getCollectionElementColumns(role, roleAlias); AssociationType elementAssociationType = sfh.getElementAssociationType(type); // Create the join element under the from element. int joinType = JoinFragment.INNER_JOIN; JoinSequence joinSequence = sfh.createJoinSequence( implied, elementAssociationType, tableAlias, joinType, targetColumns); elem = initializeJoin(path, destination, joinSequence, targetColumns, origin, false); elem.setUseFromFragment( true); // The associated entity is implied, but it must be included in the FROM. elem.setCollectionTableAlias(roleAlias); // The collection alias is the role. return elem; }
private void renderNonScalarProperties( ASTAppender appender, FromElement fromElement, int nonscalarSize, int k) { String text = fromElement.renderPropertySelect(nonscalarSize, k); appender.append(SqlTokenTypes.SQL_TOKEN, text, false); if (fromElement.getQueryableCollection() != null && fromElement.isFetch()) { text = fromElement.renderCollectionSelectFragment(nonscalarSize, k); appender.append(SqlTokenTypes.SQL_TOKEN, text, false); } // Look through the FromElement's children to find any collections of values that should be // fetched... ASTIterator iter = new ASTIterator(fromElement); while (iter.hasNext()) { FromElement child = (FromElement) iter.next(); if (child.isCollectionOfValuesOrComponents() && child.isFetch()) { // Need a better way to define the suffixes here... text = child.renderValueCollectionSelectFragment(nonscalarSize, nonscalarSize + k); appender.append(SqlTokenTypes.SQL_TOKEN, text, false); } } }
public boolean include(AST node) { FromElement fromElement = (FromElement) node; return fromElement.isFetch() && fromElement.getQueryableCollection() != null; }
public boolean include(AST node) { FromElement fromElement = (FromElement) node; return fromElement.inProjectionList(); }
public boolean include(AST node) { FromElement fromElement = (FromElement) node; return fromElement.isFromOrJoinFragment(); }
public boolean include(AST node) { final FromElement fromElement = (FromElement) node; return !fromElement.isImplied(); }
FromElement createEntityJoin( String entityClass, String tableAlias, JoinSequence joinSequence, boolean fetchFlag, boolean inFrom, EntityType type) throws SemanticException { FromElement elem = createJoin(entityClass, tableAlias, joinSequence, type, false); elem.setFetch(fetchFlag); EntityPersister entityPersister = elem.getEntityPersister(); int numberOfTables = entityPersister.getQuerySpaces().length; if (numberOfTables > 1 && implied && !elem.useFromFragment()) { if (log.isDebugEnabled()) { 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 ) ) { DotNode.useThetaStyleImplicitJoins) { // the "root from-element" in correlated subqueries do need this piece elem.setType(FROM_FRAGMENT); joinSequence.setUseThetaStyle(true); elem.setUseFromFragment(false); } } return elem; }
/** * Prepares an explicitly defined select clause. * * @param fromClause The from clause linked to this select clause. * @throws SemanticException indicates a semntic issue with the explicit select clause. */ public void initializeExplicitSelectClause(FromClause fromClause) throws SemanticException { if (prepared) { throw new IllegalStateException("SelectClause was already prepared!"); } // explicit = true; // This is an explict Select. // ArrayList sqlResultTypeList = new ArrayList(); ArrayList queryReturnTypeList = new ArrayList(); // First, collect all of the select expressions. // NOTE: This must be done *before* invoking setScalarColumnText() because setScalarColumnText() // changes the AST!!! SelectExpression[] selectExpressions = collectSelectExpressions(); // we only support parameters in select in the case of INSERT...SELECT statements if (getParameterPositions().size() > 0 && getWalker().getStatementType() != HqlSqlTokenTypes.INSERT) { throw new QueryException( "Parameters are only supported in SELECT clauses when used as part of a INSERT INTO DML statement"); } for (int i = 0; i < selectExpressions.length; i++) { SelectExpression selectExpression = selectExpressions[i]; if (AggregatedSelectExpression.class.isInstance(selectExpression)) { aggregatedSelectExpression = (AggregatedSelectExpression) selectExpression; queryReturnTypeList.addAll(aggregatedSelectExpression.getAggregatedSelectionTypeList()); scalarSelect = true; } else { // we have no choice but to do this check here // this is not very elegant but the "right way" would most likely involve a bigger rewrite // so as to // treat ParameterNodes in select clauses as SelectExpressions boolean inSubquery = selectExpression instanceof QueryNode && ((QueryNode) selectExpression).getFromClause().getParentFromClause() != null; if (getWalker().getStatementType() == HqlSqlTokenTypes.INSERT && inSubquery) { // we do not support parameters for subqueries in INSERT...SELECT if (((QueryNode) selectExpression).getSelectClause().getParameterPositions().size() > 0) { throw new QueryException( "Use of parameters in subqueries of INSERT INTO DML statements is not supported."); } } Type type = selectExpression.getDataType(); if (type == null) { throw new IllegalStateException( "No data type for node: " + selectExpression.getClass().getName() + " " + new ASTPrinter(SqlTokenTypes.class).showAsString((AST) selectExpression, "")); } // sqlResultTypeList.add( type ); // If the data type is not an association type, it could not have been in the FROM clause. if (selectExpression.isScalar()) { scalarSelect = true; } if (isReturnableEntity(selectExpression)) { fromElementsForLoad.add(selectExpression.getFromElement()); } // Always add the type to the return type list. queryReturnTypeList.add(type); } } // init the aliases, after initing the constructornode initAliases(selectExpressions); if (!getWalker().isShallowQuery()) { // add the fetched entities List fromElements = fromClause.getProjectionList(); ASTAppender appender = new ASTAppender(getASTFactory(), this); // Get ready to start adding nodes. int size = fromElements.size(); Iterator iterator = fromElements.iterator(); for (int k = 0; iterator.hasNext(); k++) { FromElement fromElement = (FromElement) iterator.next(); if (fromElement.isFetch()) { FromElement origin = null; if (fromElement.getRealOrigin() == null) { // work around that crazy issue where the tree contains // "empty" FromElements (no text); afaict, this is caused // by FromElementFactory.createCollectionJoin() if (fromElement.getOrigin() == null) { throw new QueryException( "Unable to determine origin of join fetch [" + fromElement.getDisplayText() + "]"); } else { origin = fromElement.getOrigin(); } } else { origin = fromElement.getRealOrigin(); } if (!fromElementsForLoad.contains(origin)) { throw new QueryException( "query specified join fetching, but the owner " + "of the fetched association was not present in the select list " + "[" + fromElement.getDisplayText() + "]"); } Type type = fromElement.getSelectType(); addCollectionFromElement(fromElement); if (type != null) { boolean collectionOfElements = fromElement.isCollectionOfValuesOrComponents(); if (!collectionOfElements) { // Add the type to the list of returned sqlResultTypes. fromElement.setIncludeSubclasses(true); fromElementsForLoad.add(fromElement); // sqlResultTypeList.add( type ); // Generate the select expression. String text = fromElement.renderIdentifierSelect(size, k); SelectExpressionImpl generatedExpr = (SelectExpressionImpl) appender.append(SqlTokenTypes.SELECT_EXPR, text, false); if (generatedExpr != null) { generatedExpr.setFromElement(fromElement); } } } } } // generate id select fragment and then property select fragment for // each expression, just like generateSelectFragments(). renderNonScalarSelects(collectSelectExpressions(), fromClause); } if (scalarSelect || getWalker().isShallowQuery()) { // If there are any scalars (non-entities) selected, render the select column aliases. renderScalarSelects(selectExpressions, fromClause); } finishInitialization(/*sqlResultTypeList,*/ queryReturnTypeList); }