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;
 }
  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;
  }
  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;
  }
예제 #4
0
  /**
   * 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);
  }