Package org.hibernate.hql.internal.ast.tree

Source Code of org.hibernate.hql.internal.ast.tree.InLogicOperatorNode

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*
*/
package org.hibernate.hql.internal.ast.tree;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.type.Type;

import antlr.SemanticException;
import antlr.collections.AST;

/**
* @author Steve Ebersole
*/
public class InLogicOperatorNode extends BinaryLogicOperatorNode implements BinaryOperatorNode {
  public Node getInList() {
    return getRightHandOperand();
  }

  @Override
  public void initialize() throws SemanticException {
    final Node lhs = getLeftHandOperand();
    if ( lhs == null ) {
      throw new SemanticException( "left-hand operand of in operator was null" );
    }

    final Node inList = getInList();
    if ( inList == null ) {
      throw new SemanticException( "right-hand operand of in operator was null" );
    }

    // for expected parameter type injection, we expect that the lhs represents
    // some form of property ref and that the children of the in-list represent
    // one-or-more params.
    if ( SqlNode.class.isAssignableFrom( lhs.getClass() ) ) {
      Type lhsType = ( (SqlNode) lhs ).getDataType();
      AST inListChild = inList.getFirstChild();
      while ( inListChild != null ) {
        if ( ExpectedTypeAwareNode.class.isAssignableFrom( inListChild.getClass() ) ) {
          ( (ExpectedTypeAwareNode) inListChild ).setExpectedType( lhsType );
        }
        inListChild = inListChild.getNextSibling();
      }
    }

    final SessionFactoryImplementor sessionFactory = getSessionFactoryHelper().getFactory();
    if ( sessionFactory.getDialect().supportsRowValueConstructorSyntaxInInList() ) {
      return;
    }

    final Type lhsType = extractDataType( lhs );
    if ( lhsType == null ) {
      return;
    }
    final int lhsColumnSpan = lhsType.getColumnSpan( sessionFactory );

    final Node rhsNode = (Node) inList.getFirstChild();
    if ( !isNodeAcceptable( rhsNode ) ) {
      return;
    }
    int rhsColumnSpan;
    if ( rhsNode == null ) {
      // early exit for empty IN list
      return;
    }
    else if ( rhsNode.getType() == HqlTokenTypes.VECTOR_EXPR ) {
      rhsColumnSpan = rhsNode.getNumberOfChildren();
    }
    else {
      final Type rhsType = extractDataType( rhsNode );
      if ( rhsType == null ) {
        return;
      }
      rhsColumnSpan = rhsType.getColumnSpan( sessionFactory );
    }

    if ( lhsColumnSpan > 1 && rhsColumnSpan > 1 ) {
      mutateRowValueConstructorSyntaxInInListSyntax( lhsColumnSpan, rhsColumnSpan );
    }
  }

  /**
   * this is possible for parameter lists and explicit lists. It is completely unreasonable for sub-queries.
   */
  private boolean isNodeAcceptable(Node rhsNode) {
    return rhsNode == null /* empty IN list */ || rhsNode instanceof LiteralNode
        || rhsNode instanceof ParameterNode
        || rhsNode.getType() == HqlTokenTypes.VECTOR_EXPR;
  }

  /**
   * Mutate the subtree relating to a row-value-constructor in "in" list to instead use
   * a series of ORen and ANDed predicates.  This allows multi-column type comparisons
   * and explicit row-value-constructor in "in" list syntax even on databases which do
   * not support row-value-constructor in "in" list.
   * <p/>
   * For example, here we'd mutate "... where (col1, col2) in ( ('val1', 'val2'), ('val3', 'val4') ) ..." to
   * "... where (col1 = 'val1' and col2 = 'val2') or (col1 = 'val3' and val2 = 'val4') ..."
   *
   * @param lhsColumnSpan The number of elements in the row value constructor list.
   */
  private void mutateRowValueConstructorSyntaxInInListSyntax(
      int lhsColumnSpan, int rhsColumnSpan) {
    String[] lhsElementTexts = extractMutationTexts(
        getLeftHandOperand(),
        lhsColumnSpan
    );
    Node rhsNode = (Node) getInList().getFirstChild();

    ParameterSpecification lhsEmbeddedCompositeParameterSpecification = getLeftHandOperand() == null
        || ( !ParameterNode.class.isInstance( getLeftHandOperand() ) ) ? null
        : ( (ParameterNode) getLeftHandOperand() )
        .getHqlParameterSpecification();

    final boolean negated = getType() == HqlSqlTokenTypes.NOT_IN;

    if ( rhsNode != null && rhsNode.getNextSibling() == null ) {
      /**
       * only one element in the vector grouping.
       * <code> where (a,b) in ( (1,2) ) </code> this will be mutated to
       * <code>where a=1 and b=2 </code>
       */
      String[] rhsElementTexts = extractMutationTexts( rhsNode, rhsColumnSpan );
      setType( negated ? HqlTokenTypes.OR : HqlSqlTokenTypes.AND );
      setText( negated ? "or" : "and" );
      ParameterSpecification rhsEmbeddedCompositeParameterSpecification =
          rhsNode == null || ( !ParameterNode.class.isInstance( rhsNode ) )
              ? null
              : ( (ParameterNode) rhsNode ).getHqlParameterSpecification();
      translate(
          lhsColumnSpan,
          negated ? HqlSqlTokenTypes.NE : HqlSqlTokenTypes.EQ,
          negated ? "<>" : "=",
          lhsElementTexts,
          rhsElementTexts,
          lhsEmbeddedCompositeParameterSpecification,
          rhsEmbeddedCompositeParameterSpecification,
          this
      );
    }
    else {
      List andElementsNodeList = new ArrayList();
      while ( rhsNode != null ) {
        String[] rhsElementTexts = extractMutationTexts( rhsNode, rhsColumnSpan );
        AST group = getASTFactory().create(
            negated ? HqlSqlTokenTypes.OR : HqlSqlTokenTypes.AND,
            negated ? "or" : "and"
        );
        ParameterSpecification rhsEmbeddedCompositeParameterSpecification =
            rhsNode == null || ( !ParameterNode.class.isInstance( rhsNode ) )
                ? null
                : ( (ParameterNode) rhsNode ).getHqlParameterSpecification();
        translate(
            lhsColumnSpan,
            negated ? HqlSqlTokenTypes.NE : HqlSqlTokenTypes.EQ,
            negated ? "<>" : "=",
            lhsElementTexts,
            rhsElementTexts,
            lhsEmbeddedCompositeParameterSpecification,
            rhsEmbeddedCompositeParameterSpecification,
            group
        );
        andElementsNodeList.add( group );
        rhsNode = (Node) rhsNode.getNextSibling();
      }
      setType( negated ? HqlSqlTokenTypes.AND : HqlSqlTokenTypes.OR );
      setText( negated ? "and" : "or" );
      AST curNode = this;
      for ( int i = andElementsNodeList.size() - 1; i > 1; i-- ) {
        AST group = getASTFactory().create(
            negated ? HqlSqlTokenTypes.AND : HqlSqlTokenTypes.OR,
            negated ? "and" : "or"
        );
        curNode.setFirstChild( group );
        curNode = group;
        AST and = (AST) andElementsNodeList.get( i );
        group.setNextSibling( and );
      }
      AST node0 = (AST) andElementsNodeList.get( 0 );
      AST node1 = (AST) andElementsNodeList.get( 1 );
      node0.setNextSibling( node1 );
      curNode.setFirstChild( node0 );
    }
  }
}
TOP

Related Classes of org.hibernate.hql.internal.ast.tree.InLogicOperatorNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.