org.hibernate.hql.internal.ast.tree.AbstractNullnessCheckNode Maven / Gradle / Ivy
/*
* 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 org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.type.Type;
import antlr.collections.AST;
/**
* Base class for nodes dealing 'is null' and 'is not null' operators.
*
* todo : a good deal of this is copied from BinaryLogicOperatorNode; look at consolidating these code fragments
*
* @author Steve Ebersole
*/
public abstract class AbstractNullnessCheckNode extends UnaryLogicOperatorNode {
@Override
public void initialize() {
// TODO : this really needs to be delayed unitl after we definitively know the operand node type;
// where this is currently a problem is parameters for which where we cannot unequivocally
// resolve an expected type
Type operandType = extractDataType( getOperand() );
if ( operandType == null ) {
return;
}
SessionFactoryImplementor sessionFactory = getSessionFactoryHelper().getFactory();
int operandColumnSpan = operandType.getColumnSpan( sessionFactory );
if ( operandColumnSpan > 1 ) {
mutateRowValueConstructorSyntax( operandColumnSpan );
}
}
/**
* When (if) we need to expand a row value constructor, what is the type of connector to use between the
* expansion fragments.
*
* @return The expansion connector type.
*/
protected abstract int getExpansionConnectorType();
/**
* When (if) we need to expand a row value constructor, what is the text of the connector to use between the
* expansion fragments.
*
* @return The expansion connector text.
*/
protected abstract String getExpansionConnectorText();
private void mutateRowValueConstructorSyntax(int operandColumnSpan) {
final int comparisonType = getType();
final String comparisonText = getText();
final int expansionConnectorType = getExpansionConnectorType();
final String expansionConnectorText = getExpansionConnectorText();
setType( expansionConnectorType );
setText( expansionConnectorText );
String[] mutationTexts = extractMutationTexts( getOperand(), operandColumnSpan );
AST container = this;
for ( int i = operandColumnSpan - 1; i > 0; i-- ) {
if ( i == 1 ) {
AST op1 = getASTFactory().create( comparisonType, comparisonText );
AST operand1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, mutationTexts[0] );
op1.setFirstChild( operand1 );
container.setFirstChild( op1 );
AST op2 = getASTFactory().create( comparisonType, comparisonText );
AST operand2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, mutationTexts[1] );
op2.setFirstChild( operand2 );
op1.setNextSibling( op2 );
}
else {
AST op = getASTFactory().create( comparisonType, comparisonText );
AST operand = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, mutationTexts[i] );
op.setFirstChild( operand );
AST newContainer = getASTFactory().create( expansionConnectorType, expansionConnectorText );
container.setFirstChild( newContainer );
newContainer.setNextSibling( op );
container = newContainer;
}
}
}
private static Type extractDataType(Node operand) {
if ( operand instanceof SqlNode ) {
return ( (SqlNode) operand ).getDataType();
}
if ( operand instanceof ExpectedTypeAwareNode ) {
return ( (ExpectedTypeAwareNode) operand ).getExpectedType();
}
return null;
}
private static String[] extractMutationTexts(Node operand, int count) {
if ( operand instanceof ParameterNode ) {
String[] rtn = new String[count];
for ( int i = 0; i < count; i++ ) {
rtn[i] = "?";
}
return rtn;
}
else if ( operand.getType() == HqlSqlTokenTypes.VECTOR_EXPR ) {
final String[] rtn = new String[ operand.getNumberOfChildren() ];
AST node = operand.getFirstChild();
int x = 0;
while ( node != null ) {
rtn[ x++ ] = node.getText();
node = node.getNextSibling();
}
return rtn;
}
else if ( operand instanceof SqlNode ) {
String nodeText = operand.getText();
if ( nodeText.startsWith( "(" ) ) {
nodeText = nodeText.substring( 1 );
}
if ( nodeText.endsWith( ")" ) ) {
nodeText = nodeText.substring( 0, nodeText.length() - 1 );
}
String[] splits = StringHelper.split( ", ", nodeText );
if ( count != splits.length ) {
throw new HibernateException( "SqlNode's text did not reference expected number of columns" );
}
return splits;
}
else {
throw new HibernateException( "dont know how to extract row value elements from node : " + operand );
}
}
}