HHH-4081 - Support for JPA 2.0 "qualified identification variables" (KEY, VALUE and ENTRY)
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17300 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
ad3409e67b
commit
c35efa6780
|
@ -76,6 +76,8 @@
|
||||||
<version>${antlrPluginVersion}</version>
|
<version>${antlrPluginVersion}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<grammars>hql.g,hql-sql.g,sql-gen.g,order-by.g,order-by-render.g</grammars>
|
<grammars>hql.g,hql-sql.g,sql-gen.g,order-by.g,order-by-render.g</grammars>
|
||||||
|
<traceParser>true</traceParser>
|
||||||
|
<traceTreeParser>true</traceTreeParser>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
|
|
@ -230,6 +230,10 @@ tokens
|
||||||
protected void prepareLogicOperator(AST operator) throws SemanticException { }
|
protected void prepareLogicOperator(AST operator) throws SemanticException { }
|
||||||
|
|
||||||
protected void prepareArithmeticOperator(AST operator) throws SemanticException { }
|
protected void prepareArithmeticOperator(AST operator) throws SemanticException { }
|
||||||
|
|
||||||
|
protected void processMapComponentReference(AST node) throws SemanticException { }
|
||||||
|
|
||||||
|
protected void validateMapPropertyExpression(AST node) throws SemanticException { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// The main statement rule.
|
// The main statement rule.
|
||||||
|
@ -640,7 +644,11 @@ propertyName
|
||||||
;
|
;
|
||||||
|
|
||||||
propertyRef!
|
propertyRef!
|
||||||
: #(d:DOT lhs:propertyRefLhs rhs:propertyName ) {
|
: mcr:mapComponentReference {
|
||||||
|
resolve( #mcr );
|
||||||
|
#propertyRef = #mcr;
|
||||||
|
}
|
||||||
|
| #(d:DOT lhs:propertyRefLhs rhs:propertyName ) {
|
||||||
// This gives lookupProperty() a chance to transform the tree to process collection properties (.elements, etc).
|
// This gives lookupProperty() a chance to transform the tree to process collection properties (.elements, etc).
|
||||||
#propertyRef = #(#d, #lhs, #rhs);
|
#propertyRef = #(#d, #lhs, #rhs);
|
||||||
#propertyRef = lookupProperty(#propertyRef,false,true);
|
#propertyRef = lookupProperty(#propertyRef,false,true);
|
||||||
|
@ -672,6 +680,18 @@ aliasRef!
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
mapComponentReference
|
||||||
|
: #( KEY mapPropertyExpression )
|
||||||
|
| #( VALUE mapPropertyExpression )
|
||||||
|
| #( ENTRY mapPropertyExpression )
|
||||||
|
;
|
||||||
|
|
||||||
|
mapPropertyExpression
|
||||||
|
: e:expr {
|
||||||
|
validateMapPropertyExpression( #e );
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
parameter!
|
parameter!
|
||||||
: #(c:COLON a:identifier) {
|
: #(c:COLON a:identifier) {
|
||||||
// Create a NAMED_PARAM node instead of (COLON IDENT).
|
// Create a NAMED_PARAM node instead of (COLON IDENT).
|
||||||
|
|
|
@ -99,6 +99,9 @@ tokens
|
||||||
OBJECT="object";
|
OBJECT="object";
|
||||||
OF="of";
|
OF="of";
|
||||||
TRAILING="trailing";
|
TRAILING="trailing";
|
||||||
|
KEY="key";
|
||||||
|
VALUE="value";
|
||||||
|
ENTRY="entry";
|
||||||
|
|
||||||
// -- Synthetic token types --
|
// -- Synthetic token types --
|
||||||
AGGREGATE; // One of the aggregate functions (e.g. min, max, avg)
|
AGGREGATE; // One of the aggregate functions (e.g. min, max, avg)
|
||||||
|
@ -633,7 +636,8 @@ vectorExpr
|
||||||
// NOTE: handleDotIdent() is called immediately after the first IDENT is recognized because
|
// NOTE: handleDotIdent() is called immediately after the first IDENT is recognized because
|
||||||
// the method looks a head to find keywords after DOT and turns them into identifiers.
|
// the method looks a head to find keywords after DOT and turns them into identifiers.
|
||||||
identPrimary
|
identPrimary
|
||||||
: identifier { handleDotIdent(); }
|
: mapComponentReference
|
||||||
|
| identifier { handleDotIdent(); }
|
||||||
( options { greedy=true; } : DOT^ ( identifier | ELEMENTS | o:OBJECT { #o.setType(IDENT); } ) )*
|
( options { greedy=true; } : DOT^ ( identifier | ELEMENTS | o:OBJECT { #o.setType(IDENT); } ) )*
|
||||||
( options { greedy=true; } :
|
( options { greedy=true; } :
|
||||||
( op:OPEN^ { #op.setType(METHOD_CALL);} exprList CLOSE! )
|
( op:OPEN^ { #op.setType(METHOD_CALL);} exprList CLOSE! )
|
||||||
|
@ -642,11 +646,9 @@ identPrimary
|
||||||
| aggregate
|
| aggregate
|
||||||
;
|
;
|
||||||
|
|
||||||
//## aggregate:
|
mapComponentReference
|
||||||
//## ( aggregateFunction OPEN path CLOSE ) | ( COUNT OPEN STAR CLOSE ) | ( COUNT OPEN (DISTINCT | ALL) path CLOSE );
|
: ( KEY^ | VALUE^ | ENTRY^ ) OPEN! path CLOSE!
|
||||||
|
;
|
||||||
//## aggregateFunction:
|
|
||||||
//## COUNT | 'sum' | 'avg' | 'max' | 'min';
|
|
||||||
|
|
||||||
aggregate
|
aggregate
|
||||||
: ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! additiveExpression CLOSE! { #aggregate.setType(AGGREGATE); }
|
: ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! additiveExpression CLOSE! { #aggregate.setType(AGGREGATE); }
|
||||||
|
|
|
@ -207,6 +207,7 @@ selectColumn
|
||||||
|
|
||||||
selectExpr
|
selectExpr
|
||||||
: e:selectAtom { out(e); }
|
: e:selectAtom { out(e); }
|
||||||
|
| mcr:mapComponentReference { out(mcr); }
|
||||||
| count
|
| count
|
||||||
| #(CONSTRUCTOR (DOT | IDENT) ( selectColumn )+ )
|
| #(CONSTRUCTOR (DOT | IDENT) ( selectColumn )+ )
|
||||||
| methodCall
|
| methodCall
|
||||||
|
@ -240,6 +241,12 @@ selectAtom
|
||||||
| SELECT_EXPR
|
| SELECT_EXPR
|
||||||
;
|
;
|
||||||
|
|
||||||
|
mapComponentReference
|
||||||
|
: KEY
|
||||||
|
| VALUE
|
||||||
|
| ENTRY
|
||||||
|
;
|
||||||
|
|
||||||
// The from-clause piece is all goofed up. Currently, nodes of type FROM_FRAGMENT
|
// The from-clause piece is all goofed up. Currently, nodes of type FROM_FRAGMENT
|
||||||
// and JOIN_FRAGMENT can occur at any level in the FromClause sub-tree. We really
|
// and JOIN_FRAGMENT can occur at any level in the FromClause sub-tree. We really
|
||||||
// should come back and clean this up at some point; which I think will require
|
// should come back and clean this up at some point; which I think will require
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.hibernate.hql.antlr.HqlTokenTypes;
|
||||||
import org.hibernate.hql.ast.util.ASTPrinter;
|
import org.hibernate.hql.ast.util.ASTPrinter;
|
||||||
import org.hibernate.hql.ast.util.ASTUtil;
|
import org.hibernate.hql.ast.util.ASTUtil;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the semantic action methods defined in the HQL base parser to keep the grammar
|
* Implements the semantic action methods defined in the HQL base parser to keep the grammar
|
||||||
|
@ -73,6 +74,28 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private int traceDepth = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public void traceIn(String ruleName) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void traceOut(String ruleName) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
|
|
||||||
public void reportError(RecognitionException e) {
|
public void reportError(RecognitionException e) {
|
||||||
parseErrorHandler.reportError( e ); // Use the delegate.
|
parseErrorHandler.reportError( e ); // Use the delegate.
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,7 @@ import org.hibernate.type.VersionType;
|
||||||
import org.hibernate.type.DbTimestampType;
|
import org.hibernate.type.DbTimestampType;
|
||||||
import org.hibernate.usertype.UserVersionType;
|
import org.hibernate.usertype.UserVersionType;
|
||||||
import org.hibernate.util.ArrayHelper;
|
import org.hibernate.util.ArrayHelper;
|
||||||
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
import antlr.ASTFactory;
|
import antlr.ASTFactory;
|
||||||
import antlr.RecognitionException;
|
import antlr.RecognitionException;
|
||||||
|
@ -169,6 +170,34 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private int traceDepth = 0;
|
||||||
|
|
||||||
|
public void traceIn(String ruleName, AST tree) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
||||||
|
String traceText = ruleName + " (" + buildTraceNodeName(tree) + ")";
|
||||||
|
log.trace( prefix + traceText );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildTraceNodeName(AST tree) {
|
||||||
|
return tree == null
|
||||||
|
? "???"
|
||||||
|
: tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void traceOut(String ruleName, AST tree) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void prepareFromClauseInputTree(AST fromClauseInput) {
|
protected void prepareFromClauseInputTree(AST fromClauseInput) {
|
||||||
if ( !isSubQuery() ) {
|
if ( !isSubQuery() ) {
|
||||||
// // inject param specifications to account for dynamic filter param values
|
// // inject param specifications to account for dynamic filter param values
|
||||||
|
@ -826,11 +855,12 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
||||||
// This is called when it's time to fully resolve a path expression.
|
// This is called when it's time to fully resolve a path expression.
|
||||||
int type = node.getType();
|
int type = node.getType();
|
||||||
switch ( type ) {
|
switch ( type ) {
|
||||||
case DOT:
|
case DOT: {
|
||||||
DotNode dot = ( DotNode ) node;
|
DotNode dot = ( DotNode ) node;
|
||||||
dot.resolveSelectExpression();
|
dot.resolveSelectExpression();
|
||||||
break;
|
break;
|
||||||
case ALIAS_REF:
|
}
|
||||||
|
case ALIAS_REF: {
|
||||||
// Notify the FROM element that it is being referenced by the select.
|
// Notify the FROM element that it is being referenced by the select.
|
||||||
FromReferenceNode aliasRefNode = ( FromReferenceNode ) node;
|
FromReferenceNode aliasRefNode = ( FromReferenceNode ) node;
|
||||||
//aliasRefNode.resolve( false, false, aliasRefNode.getText() ); //TODO: is it kosher to do it here?
|
//aliasRefNode.resolve( false, false, aliasRefNode.getText() ); //TODO: is it kosher to do it here?
|
||||||
|
@ -839,8 +869,11 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
||||||
if ( fromElement != null ) {
|
if ( fromElement != null ) {
|
||||||
fromElement.setIncludeSubclasses( true );
|
fromElement.setIncludeSubclasses( true );
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1101,6 +1134,22 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
||||||
( ( OperatorNode ) operator ).initialize();
|
( ( OperatorNode ) operator ).initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void validateMapPropertyExpression(AST node) throws SemanticException {
|
||||||
|
try {
|
||||||
|
FromReferenceNode fromReferenceNode = (FromReferenceNode) node;
|
||||||
|
QueryableCollection collectionPersister = fromReferenceNode.getFromElement().getQueryableCollection();
|
||||||
|
if ( ! Map.class.isAssignableFrom( collectionPersister.getCollectionType().getReturnedClass() ) ) {
|
||||||
|
throw new SemanticException( "node did not reference a map" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( SemanticException se ) {
|
||||||
|
throw se;
|
||||||
|
}
|
||||||
|
catch ( Throwable t ) {
|
||||||
|
throw new SemanticException( "node did not reference a map" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void panic() {
|
public static void panic() {
|
||||||
throw new QueryException( "TreeWalker: panic" );
|
throw new QueryException( "TreeWalker: panic" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,7 +288,6 @@ public class QueryTranslatorImpl implements FilterTranslator {
|
||||||
void showHqlAst(AST hqlAst) {
|
void showHqlAst(AST hqlAst) {
|
||||||
if ( AST_LOG.isDebugEnabled() ) {
|
if ( AST_LOG.isDebugEnabled() ) {
|
||||||
ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class );
|
ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class );
|
||||||
printer.setShowClassNames( false ); // The class names aren't interesting in the first tree.
|
|
||||||
AST_LOG.debug( printer.showAsString( hqlAst, "--- HQL AST ---" ) );
|
AST_LOG.debug( printer.showAsString( hqlAst, "--- HQL AST ---" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,9 @@ import org.hibernate.hql.ast.tree.SessionFactoryAwareNode;
|
||||||
import org.hibernate.hql.ast.tree.BooleanLiteralNode;
|
import org.hibernate.hql.ast.tree.BooleanLiteralNode;
|
||||||
import org.hibernate.hql.ast.tree.IsNullLogicOperatorNode;
|
import org.hibernate.hql.ast.tree.IsNullLogicOperatorNode;
|
||||||
import org.hibernate.hql.ast.tree.IsNotNullLogicOperatorNode;
|
import org.hibernate.hql.ast.tree.IsNotNullLogicOperatorNode;
|
||||||
|
import org.hibernate.hql.ast.tree.MapKeyNode;
|
||||||
|
import org.hibernate.hql.ast.tree.MapValueNode;
|
||||||
|
import org.hibernate.hql.ast.tree.MapEntryNode;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
|
@ -187,6 +190,15 @@ public class SqlASTFactory extends ASTFactory implements HqlSqlTokenTypes {
|
||||||
return IsNotNullLogicOperatorNode.class;
|
return IsNotNullLogicOperatorNode.class;
|
||||||
case EXISTS:
|
case EXISTS:
|
||||||
return UnaryLogicOperatorNode.class;
|
return UnaryLogicOperatorNode.class;
|
||||||
|
case KEY: {
|
||||||
|
return MapKeyNode.class;
|
||||||
|
}
|
||||||
|
case VALUE: {
|
||||||
|
return MapValueNode.class;
|
||||||
|
}
|
||||||
|
case ENTRY: {
|
||||||
|
return MapEntryNode.class;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return SqlNode.class;
|
return SqlNode.class;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
|
@ -32,15 +32,21 @@ import java.util.Arrays;
|
||||||
import antlr.RecognitionException;
|
import antlr.RecognitionException;
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
|
import org.hibernate.util.StringHelper;
|
||||||
import org.hibernate.param.ParameterSpecification;
|
import org.hibernate.param.ParameterSpecification;
|
||||||
import org.hibernate.dialect.function.SQLFunction;
|
import org.hibernate.dialect.function.SQLFunction;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.hql.antlr.SqlGeneratorBase;
|
import org.hibernate.hql.antlr.SqlGeneratorBase;
|
||||||
|
import org.hibernate.hql.antlr.SqlTokenTypes;
|
||||||
import org.hibernate.hql.ast.tree.MethodNode;
|
import org.hibernate.hql.ast.tree.MethodNode;
|
||||||
import org.hibernate.hql.ast.tree.FromElement;
|
import org.hibernate.hql.ast.tree.FromElement;
|
||||||
import org.hibernate.hql.ast.tree.Node;
|
import org.hibernate.hql.ast.tree.Node;
|
||||||
import org.hibernate.hql.ast.tree.ParameterNode;
|
import org.hibernate.hql.ast.tree.ParameterNode;
|
||||||
import org.hibernate.hql.ast.tree.ParameterContainer;
|
import org.hibernate.hql.ast.tree.ParameterContainer;
|
||||||
|
import org.hibernate.hql.ast.util.ASTPrinter;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates SQL by overriding callback methods in the base class, which does
|
* Generates SQL by overriding callback methods in the base class, which does
|
||||||
|
@ -50,10 +56,7 @@ import org.hibernate.hql.ast.tree.ParameterContainer;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
|
public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
|
||||||
/**
|
private static final Logger log = LoggerFactory.getLogger( SqlGenerator.class );
|
||||||
* Handles parser errors.
|
|
||||||
*/
|
|
||||||
private ParseErrorHandler parseErrorHandler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* all append invocations on the buf should go through this Output instance variable.
|
* all append invocations on the buf should go through this Output instance variable.
|
||||||
|
@ -64,12 +67,40 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
|
||||||
*/
|
*/
|
||||||
private SqlWriter writer = new DefaultWriter();
|
private SqlWriter writer = new DefaultWriter();
|
||||||
|
|
||||||
|
private ParseErrorHandler parseErrorHandler;
|
||||||
private SessionFactoryImplementor sessionFactory;
|
private SessionFactoryImplementor sessionFactory;
|
||||||
|
|
||||||
private LinkedList outputStack = new LinkedList();
|
private LinkedList outputStack = new LinkedList();
|
||||||
|
private final ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class );
|
||||||
private List collectedParameters = new ArrayList();
|
private List collectedParameters = new ArrayList();
|
||||||
|
|
||||||
|
|
||||||
|
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private int traceDepth = 0;
|
||||||
|
|
||||||
|
public void traceIn(String ruleName, AST tree) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
||||||
|
String traceText = ruleName + " (" + buildTraceNodeName(tree) + ")";
|
||||||
|
log.trace( prefix + traceText );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildTraceNodeName(AST tree) {
|
||||||
|
return tree == null
|
||||||
|
? "???"
|
||||||
|
: tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void traceOut(String ruleName, AST tree) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
|
|
||||||
public List getCollectedParameters() {
|
public List getCollectedParameters() {
|
||||||
return collectedParameters;
|
return collectedParameters;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ast.tree;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import antlr.SemanticException;
|
||||||
|
import antlr.collections.AST;
|
||||||
|
|
||||||
|
import org.hibernate.hql.antlr.HqlSqlTokenTypes;
|
||||||
|
import org.hibernate.hql.ast.util.ColumnHelper;
|
||||||
|
import org.hibernate.type.CollectionType;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMapComponentNode extends FromReferenceNode implements HqlSqlTokenTypes {
|
||||||
|
private String[] columns;
|
||||||
|
|
||||||
|
public FromReferenceNode getMapReference() {
|
||||||
|
return ( FromReferenceNode ) getFirstChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getColumns() {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScalarColumnText(int i) throws SemanticException {
|
||||||
|
ColumnHelper.generateScalarColumns( this, getColumns(), i );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolve(
|
||||||
|
boolean generateJoin,
|
||||||
|
boolean implicitJoin,
|
||||||
|
String classAlias,
|
||||||
|
AST parent) throws SemanticException {
|
||||||
|
if ( parent != null ) {
|
||||||
|
throw attemptedDereference();
|
||||||
|
}
|
||||||
|
|
||||||
|
FromReferenceNode mapReference = getMapReference();
|
||||||
|
mapReference.resolve( true, true );
|
||||||
|
if ( mapReference.getDataType().isCollectionType() ) {
|
||||||
|
CollectionType collectionType = (CollectionType) mapReference.getDataType();
|
||||||
|
if ( Map.class.isAssignableFrom( collectionType.getReturnedClass() ) ) {
|
||||||
|
FromElement sourceFromElement = mapReference.getFromElement();
|
||||||
|
setFromElement( sourceFromElement );
|
||||||
|
setDataType( resolveType( sourceFromElement.getQueryableCollection() ) );
|
||||||
|
this.columns = resolveColumns( sourceFromElement.getQueryableCollection() );
|
||||||
|
initText( this.columns );
|
||||||
|
setFirstChild( null );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw nonMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initText(String[] columns) {
|
||||||
|
String text = StringHelper.join( ", ", columns );
|
||||||
|
if ( columns.length > 1 && getWalker().isComparativeExpressionClause() ) {
|
||||||
|
text = "(" + text + ")";
|
||||||
|
}
|
||||||
|
setText( text );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String expressionDescription();
|
||||||
|
protected abstract String[] resolveColumns(QueryableCollection collectionPersister);
|
||||||
|
protected abstract Type resolveType(QueryableCollection collectionPersister);
|
||||||
|
|
||||||
|
protected SemanticException attemptedDereference() {
|
||||||
|
return new SemanticException( expressionDescription() + " expression cannot be further de-referenced" );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SemanticException nonMap() {
|
||||||
|
return new SemanticException( expressionDescription() + " expression did not reference map property" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolveIndex(AST parent) throws SemanticException {
|
||||||
|
throw new UnsupportedOperationException( expressionDescription() + " expression cannot be the source for an index operation" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ast.tree;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.transform.ResultTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contract for a select expression which aggregates other select expressions together into a single return
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface AggregatedSelectExpression extends SelectExpression {
|
||||||
|
/**
|
||||||
|
* Retrieves a list of the selection {@link org.hibernate.type.Type types} being aggregated
|
||||||
|
*
|
||||||
|
* @return The list of types.
|
||||||
|
*/
|
||||||
|
public List getAggregatedSelectionTypeList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the aliases for the columns aggregated here.
|
||||||
|
*
|
||||||
|
* @return The column aliases.
|
||||||
|
*/
|
||||||
|
public String[] getAggregatedAliases();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the {@link ResultTransformer} responsible for building aggregated select expression results into their
|
||||||
|
* aggregated form.
|
||||||
|
*
|
||||||
|
* @return The appropriate transformer
|
||||||
|
*/
|
||||||
|
public ResultTransformer getResultTransformer();
|
||||||
|
}
|
|
@ -29,6 +29,10 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.PropertyNotFoundException;
|
import org.hibernate.PropertyNotFoundException;
|
||||||
|
import org.hibernate.QueryException;
|
||||||
|
import org.hibernate.transform.ResultTransformer;
|
||||||
|
import org.hibernate.transform.AliasToBeanConstructorResultTransformer;
|
||||||
|
import org.hibernate.transform.Transformers;
|
||||||
import org.hibernate.hql.ast.DetailedSemanticException;
|
import org.hibernate.hql.ast.DetailedSemanticException;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.util.ReflectHelper;
|
import org.hibernate.util.ReflectHelper;
|
||||||
|
@ -42,13 +46,25 @@ import antlr.collections.AST;
|
||||||
*
|
*
|
||||||
* @author josh
|
* @author josh
|
||||||
*/
|
*/
|
||||||
public class ConstructorNode extends SelectExpressionList implements SelectExpression {
|
public class ConstructorNode extends SelectExpressionList implements AggregatedSelectExpression {
|
||||||
|
|
||||||
private Constructor constructor;
|
private Constructor constructor;
|
||||||
private Type[] constructorArgumentTypes;
|
private Type[] constructorArgumentTypes;
|
||||||
private boolean isMap;
|
private boolean isMap;
|
||||||
private boolean isList;
|
private boolean isList;
|
||||||
|
|
||||||
|
public ResultTransformer getResultTransformer() {
|
||||||
|
if ( constructor != null ) {
|
||||||
|
return new AliasToBeanConstructorResultTransformer( constructor );
|
||||||
|
}
|
||||||
|
else if ( isMap ) {
|
||||||
|
return Transformers.ALIAS_TO_ENTITY_MAP;
|
||||||
|
}
|
||||||
|
else if ( isList ) {
|
||||||
|
return Transformers.TO_LIST;
|
||||||
|
}
|
||||||
|
throw new QueryException( "Unable to determine proper dynamic-instantiation tranformer to use." );
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMap() {
|
public boolean isMap() {
|
||||||
return isMap;
|
return isMap;
|
||||||
}
|
}
|
||||||
|
@ -56,8 +72,17 @@ public class ConstructorNode extends SelectExpressionList implements SelectExpre
|
||||||
public boolean isList() {
|
public boolean isList() {
|
||||||
return isList;
|
return isList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getAliases() {
|
private String[] aggregatedAliases;
|
||||||
|
|
||||||
|
public String[] getAggregatedAliases() {
|
||||||
|
if ( aggregatedAliases == null ) {
|
||||||
|
aggregatedAliases = buildAggregatedAliases();
|
||||||
|
}
|
||||||
|
return aggregatedAliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] buildAggregatedAliases() {
|
||||||
SelectExpression[] selectExpressions = collectSelectExpressions();
|
SelectExpression[] selectExpressions = collectSelectExpressions();
|
||||||
String[] aliases = new String[selectExpressions.length] ;
|
String[] aliases = new String[selectExpressions.length] ;
|
||||||
for ( int i=0; i<selectExpressions.length; i++ ) {
|
for ( int i=0; i<selectExpressions.length; i++ ) {
|
||||||
|
@ -154,6 +179,10 @@ public class ConstructorNode extends SelectExpressionList implements SelectExpre
|
||||||
return Arrays.asList( constructorArgumentTypes );
|
return Arrays.asList( constructorArgumentTypes );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List getAggregatedSelectionTypeList() {
|
||||||
|
return getConstructorArgumentTypeList();
|
||||||
|
}
|
||||||
|
|
||||||
public FromElement getFromElement() {
|
public FromElement getFromElement() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import org.hibernate.QueryException;
|
||||||
import org.hibernate.engine.JoinSequence;
|
import org.hibernate.engine.JoinSequence;
|
||||||
import org.hibernate.hql.CollectionProperties;
|
import org.hibernate.hql.CollectionProperties;
|
||||||
import org.hibernate.hql.antlr.SqlTokenTypes;
|
import org.hibernate.hql.antlr.SqlTokenTypes;
|
||||||
import org.hibernate.hql.ast.util.ASTPrinter;
|
|
||||||
import org.hibernate.hql.ast.util.ASTUtil;
|
import org.hibernate.hql.ast.util.ASTUtil;
|
||||||
import org.hibernate.hql.ast.util.ColumnHelper;
|
import org.hibernate.hql.ast.util.ColumnHelper;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
|
@ -140,7 +139,7 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
FromElement fromElement = getFromElement();
|
FromElement fromElement = getFromElement();
|
||||||
buf.append( "{propertyName=" ).append( propertyName );
|
buf.append( "{propertyName=" ).append( propertyName );
|
||||||
buf.append( ",dereferenceType=" ).append( ASTPrinter.getConstantName( getClass(), dereferenceType ) );
|
buf.append( ",dereferenceType=" ).append( getWalker().getASTPrinter().getTokenTypeName( dereferenceType ) );
|
||||||
buf.append( ",propertyPath=" ).append( propertyPath );
|
buf.append( ",propertyPath=" ).append( propertyPath );
|
||||||
buf.append( ",path=" ).append( getPath() );
|
buf.append( ",path=" ).append( getPath() );
|
||||||
if ( fromElement != null ) {
|
if ( fromElement != null ) {
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ast.tree;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import antlr.SemanticException;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.sql.SelectExpression;
|
||||||
|
import org.hibernate.sql.AliasGenerator;
|
||||||
|
import org.hibernate.sql.SelectFragment;
|
||||||
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.hql.NameGenerator;
|
||||||
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
|
import org.hibernate.persister.entity.Queryable;
|
||||||
|
import org.hibernate.transform.BasicTransformerAdapter;
|
||||||
|
import org.hibernate.transform.ResultTransformer;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.type.EntityType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class MapEntryNode extends AbstractMapComponentNode implements AggregatedSelectExpression {
|
||||||
|
private static class LocalAliasGenerator implements AliasGenerator {
|
||||||
|
private final int base;
|
||||||
|
private int counter = 0;
|
||||||
|
|
||||||
|
private LocalAliasGenerator(int base) {
|
||||||
|
this.base = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateAlias(String sqlExpression) {
|
||||||
|
return NameGenerator.scalarName( base, counter++ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String expressionDescription() {
|
||||||
|
return "entry(*)";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Type resolveType(QueryableCollection collectionPersister) {
|
||||||
|
Type keyType = collectionPersister.getIndexType();
|
||||||
|
Type valueType = collectionPersister.getElementType();
|
||||||
|
types.add( keyType );
|
||||||
|
types.add( valueType );
|
||||||
|
mapEntryBuilder = new MapEntryBuilder();
|
||||||
|
|
||||||
|
// an entry (as an aggregated select expression) does not have a type...
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] resolveColumns(QueryableCollection collectionPersister) {
|
||||||
|
List selections = new ArrayList();
|
||||||
|
determineKeySelectExpressions( collectionPersister, selections );
|
||||||
|
determineValueSelectExpressions( collectionPersister, selections );
|
||||||
|
|
||||||
|
String text = "";
|
||||||
|
String[] columns = new String[selections.size()];
|
||||||
|
for ( int i = 0; i < selections.size(); i++ ) {
|
||||||
|
SelectExpression selectExpression = (SelectExpression) selections.get(i);
|
||||||
|
text += ( ", " + selectExpression.getExpression() + " as " + selectExpression.getAlias() );
|
||||||
|
columns[i] = selectExpression.getExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
text = text.substring( 2 ); //strip leading ", "
|
||||||
|
setText( text );
|
||||||
|
setResolved();
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void determineKeySelectExpressions(QueryableCollection collectionPersister, List selections) {
|
||||||
|
AliasGenerator aliasGenerator = new LocalAliasGenerator( 0 );
|
||||||
|
appendSelectExpressions( collectionPersister.getIndexColumnNames(), selections, aliasGenerator );
|
||||||
|
Type keyType = collectionPersister.getIndexType();
|
||||||
|
if ( keyType.isAssociationType() ) {
|
||||||
|
EntityType entityType = (EntityType) keyType;
|
||||||
|
Queryable keyEntityPersister = ( Queryable ) sfi().getEntityPersister(
|
||||||
|
entityType.getAssociatedEntityName( sfi() )
|
||||||
|
);
|
||||||
|
SelectFragment fragment = keyEntityPersister.propertySelectFragmentFragment(
|
||||||
|
collectionTableAlias(),
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
appendSelectExpressions( fragment, selections, aliasGenerator );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendSelectExpressions(String[] columnNames, List selections, AliasGenerator aliasGenerator) {
|
||||||
|
for ( int i = 0; i < columnNames.length; i++ ) {
|
||||||
|
selections.add(
|
||||||
|
new BasicSelectExpression(
|
||||||
|
collectionTableAlias() + '.' + columnNames[i],
|
||||||
|
aliasGenerator.generateAlias( columnNames[i] )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendSelectExpressions(SelectFragment fragment, List selections, AliasGenerator aliasGenerator) {
|
||||||
|
Iterator itr = fragment.getColumns().iterator();
|
||||||
|
while ( itr.hasNext() ) {
|
||||||
|
final String column = (String) itr.next();
|
||||||
|
selections.add(
|
||||||
|
new BasicSelectExpression( column, aliasGenerator.generateAlias( column ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void determineValueSelectExpressions(QueryableCollection collectionPersister, List selections) {
|
||||||
|
AliasGenerator aliasGenerator = new LocalAliasGenerator( 1 );
|
||||||
|
appendSelectExpressions( collectionPersister.getElementColumnNames(), selections, aliasGenerator );
|
||||||
|
Type valueType = collectionPersister.getElementType();
|
||||||
|
if ( valueType.isAssociationType() ) {
|
||||||
|
EntityType valueEntityType = (EntityType) valueType;
|
||||||
|
Queryable valueEntityPersister = ( Queryable ) sfi().getEntityPersister(
|
||||||
|
valueEntityType.getAssociatedEntityName( sfi() )
|
||||||
|
);
|
||||||
|
SelectFragment fragment = valueEntityPersister.propertySelectFragmentFragment(
|
||||||
|
elementTableAlias(),
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
appendSelectExpressions( fragment, selections, aliasGenerator );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String collectionTableAlias() {
|
||||||
|
return getFromElement().getCollectionTableAlias() != null
|
||||||
|
? getFromElement().getCollectionTableAlias()
|
||||||
|
: getFromElement().getTableAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String elementTableAlias() {
|
||||||
|
return getFromElement().getTableAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BasicSelectExpression implements SelectExpression {
|
||||||
|
private final String expression;
|
||||||
|
private final String alias;
|
||||||
|
|
||||||
|
private BasicSelectExpression(String expression, String alias) {
|
||||||
|
this.expression = expression;
|
||||||
|
this.alias = alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpression() {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlias() {
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionFactoryImplementor sfi() {
|
||||||
|
return getSessionFactoryHelper().getFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String s) {
|
||||||
|
if ( isResolved() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.setText( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScalarColumnText(int i) throws SemanticException {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isScalar() {
|
||||||
|
// Constructors are always considered scalar results.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List types = new ArrayList(4); // size=4 to prevent resizing
|
||||||
|
|
||||||
|
public List getAggregatedSelectionTypeList() {
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] ALIASES = { null, null };
|
||||||
|
|
||||||
|
public String[] getAggregatedAliases() {
|
||||||
|
return ALIASES;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapEntryBuilder mapEntryBuilder;
|
||||||
|
|
||||||
|
public ResultTransformer getResultTransformer() {
|
||||||
|
return mapEntryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MapEntryBuilder extends BasicTransformerAdapter {
|
||||||
|
public Object transformTuple(Object[] tuple, String[] aliases) {
|
||||||
|
if ( tuple.length != 2 ) {
|
||||||
|
throw new HibernateException( "Expecting exactly 2 tuples to transform into Map.Entry" );
|
||||||
|
}
|
||||||
|
return new EntryAdapter( tuple[0], tuple[1] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class EntryAdapter implements Map.Entry {
|
||||||
|
private final Object key;
|
||||||
|
private Object value;
|
||||||
|
|
||||||
|
private EntryAdapter(Object key, Object value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object setValue(Object value) {
|
||||||
|
Object old = this.value;
|
||||||
|
this.value = value;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
// IMPL NOTE : nulls are considered equal for keys and values according to Map.Entry contract
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( o == null || getClass() != o.getClass() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EntryAdapter that = ( EntryAdapter ) o;
|
||||||
|
|
||||||
|
// make sure we have the same types...
|
||||||
|
return ( key == null ? that.key == null : key.equals( that.key ) )
|
||||||
|
&& ( value == null ? that.value == null : value.equals( that.value ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int keyHash = key == null ? 0 : key.hashCode();
|
||||||
|
int valueHash = value == null ? 0 : value.hashCode();
|
||||||
|
return keyHash ^ valueHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ast.tree;
|
||||||
|
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class MapKeyNode extends AbstractMapComponentNode {
|
||||||
|
protected String expressionDescription() {
|
||||||
|
return "key(*)";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] resolveColumns(QueryableCollection collectionPersister) {
|
||||||
|
return collectionPersister.getIndexColumnNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Type resolveType(QueryableCollection collectionPersister) {
|
||||||
|
return collectionPersister.getIndexType();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ast.tree;
|
||||||
|
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class MapValueNode extends AbstractMapComponentNode {
|
||||||
|
protected String expressionDescription() {
|
||||||
|
return "value(*)";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] resolveColumns(QueryableCollection collectionPersister) {
|
||||||
|
return collectionPersister.getElementColumnNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Type resolveType(QueryableCollection collectionPersister) {
|
||||||
|
return collectionPersister.getElementType();
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.hql.ast.tree;
|
package org.hibernate.hql.ast.tree;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -53,10 +52,12 @@ public class SelectClause extends SelectExpressionList {
|
||||||
//private Type[] sqlResultTypes;
|
//private Type[] sqlResultTypes;
|
||||||
private Type[] queryReturnTypes;
|
private Type[] queryReturnTypes;
|
||||||
private String[][] columnNames;
|
private String[][] columnNames;
|
||||||
private ConstructorNode constructorNode;
|
|
||||||
private List collectionFromElements;
|
private List collectionFromElements;
|
||||||
private String[] aliases;
|
private String[] aliases;
|
||||||
|
|
||||||
|
// Currently we can only have one...
|
||||||
|
private AggregatedSelectExpression aggregatedSelectExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this SelectClause represent a scalar query
|
* Does this SelectClause represent a scalar query
|
||||||
*
|
*
|
||||||
|
@ -99,6 +100,8 @@ public class SelectClause extends SelectExpressionList {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HQL aliases, or generated aliases
|
* The HQL aliases, or generated aliases
|
||||||
|
*
|
||||||
|
* @return the aliases
|
||||||
*/
|
*/
|
||||||
public String[] getQueryReturnAliases() {
|
public String[] getQueryReturnAliases() {
|
||||||
return aliases;
|
return aliases;
|
||||||
|
@ -113,29 +116,15 @@ public class SelectClause extends SelectExpressionList {
|
||||||
return columnNames;
|
return columnNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public AggregatedSelectExpression getAggregatedSelectExpression() {
|
||||||
* The constructor to use for dynamic instantiation queries.
|
return aggregatedSelectExpression;
|
||||||
*
|
|
||||||
* @return The appropriate Constructor reference, or null if not a
|
|
||||||
* dynamic instantiation query.
|
|
||||||
*/
|
|
||||||
public Constructor getConstructor() {
|
|
||||||
return constructorNode == null ? null : constructorNode.getConstructor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMap() {
|
|
||||||
return constructorNode == null ? false : constructorNode.isMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isList() {
|
|
||||||
return constructorNode == null ? false : constructorNode.isList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares an explicitly defined select clause.
|
* Prepares an explicitly defined select clause.
|
||||||
*
|
*
|
||||||
* @param fromClause The from clause linked to this select clause.
|
* @param fromClause The from clause linked to this select clause.
|
||||||
* @throws SemanticException
|
* @throws SemanticException indicates a semntic issue with the explicit select clause.
|
||||||
*/
|
*/
|
||||||
public void initializeExplicitSelectClause(FromClause fromClause) throws SemanticException {
|
public void initializeExplicitSelectClause(FromClause fromClause) throws SemanticException {
|
||||||
if ( prepared ) {
|
if ( prepared ) {
|
||||||
|
@ -152,30 +141,28 @@ public class SelectClause extends SelectExpressionList {
|
||||||
SelectExpression[] selectExpressions = collectSelectExpressions();
|
SelectExpression[] selectExpressions = collectSelectExpressions();
|
||||||
|
|
||||||
for ( int i = 0; i < selectExpressions.length; i++ ) {
|
for ( int i = 0; i < selectExpressions.length; i++ ) {
|
||||||
SelectExpression expr = selectExpressions[i];
|
SelectExpression selectExpression = selectExpressions[i];
|
||||||
|
|
||||||
if ( expr.isConstructor() ) {
|
if ( AggregatedSelectExpression.class.isInstance( selectExpression ) ) {
|
||||||
constructorNode = ( ConstructorNode ) expr;
|
aggregatedSelectExpression = (AggregatedSelectExpression) selectExpression;
|
||||||
List constructorArgumentTypeList = constructorNode.getConstructorArgumentTypeList();
|
queryReturnTypeList.addAll( aggregatedSelectExpression.getAggregatedSelectionTypeList() );
|
||||||
//sqlResultTypeList.addAll( constructorArgumentTypeList );
|
|
||||||
queryReturnTypeList.addAll( constructorArgumentTypeList );
|
|
||||||
scalarSelect = true;
|
scalarSelect = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Type type = expr.getDataType();
|
Type type = selectExpression.getDataType();
|
||||||
if ( type == null ) {
|
if ( type == null ) {
|
||||||
throw new IllegalStateException( "No data type for node: " + expr.getClass().getName() + " "
|
throw new IllegalStateException( "No data type for node: " + selectExpression.getClass().getName() + " "
|
||||||
+ new ASTPrinter( SqlTokenTypes.class ).showAsString( ( AST ) expr, "" ) );
|
+ new ASTPrinter( SqlTokenTypes.class ).showAsString( ( AST ) selectExpression, "" ) );
|
||||||
}
|
}
|
||||||
//sqlResultTypeList.add( type );
|
//sqlResultTypeList.add( type );
|
||||||
|
|
||||||
// If the data type is not an association type, it could not have been in the FROM clause.
|
// If the data type is not an association type, it could not have been in the FROM clause.
|
||||||
if ( expr.isScalar() ) {
|
if ( selectExpression.isScalar() ) {
|
||||||
scalarSelect = true;
|
scalarSelect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isReturnableEntity( expr ) ) {
|
if ( isReturnableEntity( selectExpression ) ) {
|
||||||
fromElementsForLoad.add( expr.getFromElement() );
|
fromElementsForLoad.add( selectExpression.getFromElement() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always add the type to the return type list.
|
// Always add the type to the return type list.
|
||||||
|
@ -253,8 +240,7 @@ public class SelectClause extends SelectExpressionList {
|
||||||
finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
|
finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishInitialization(/*ArrayList sqlResultTypeList,*/ ArrayList queryReturnTypeList) {
|
private void finishInitialization(ArrayList queryReturnTypeList) {
|
||||||
//sqlResultTypes = ( Type[] ) sqlResultTypeList.toArray( new Type[sqlResultTypeList.size()] );
|
|
||||||
queryReturnTypes = ( Type[] ) queryReturnTypeList.toArray( new Type[queryReturnTypeList.size()] );
|
queryReturnTypes = ( Type[] ) queryReturnTypeList.toArray( new Type[queryReturnTypeList.size()] );
|
||||||
initializeColumnNames();
|
initializeColumnNames();
|
||||||
prepared = true;
|
prepared = true;
|
||||||
|
@ -287,7 +273,6 @@ public class SelectClause extends SelectExpressionList {
|
||||||
|
|
||||||
ASTAppender appender = new ASTAppender( getASTFactory(), this ); // Get ready to start adding nodes.
|
ASTAppender appender = new ASTAppender( getASTFactory(), this ); // Get ready to start adding nodes.
|
||||||
int size = fromElements.size();
|
int size = fromElements.size();
|
||||||
ArrayList sqlResultTypeList = new ArrayList( size );
|
|
||||||
ArrayList queryReturnTypeList = new ArrayList( size );
|
ArrayList queryReturnTypeList = new ArrayList( size );
|
||||||
|
|
||||||
Iterator iterator = fromElements.iterator();
|
Iterator iterator = fromElements.iterator();
|
||||||
|
@ -305,7 +290,6 @@ public class SelectClause extends SelectExpressionList {
|
||||||
queryReturnTypeList.add( type );
|
queryReturnTypeList.add( type );
|
||||||
}
|
}
|
||||||
fromElementsForLoad.add( fromElement );
|
fromElementsForLoad.add( fromElement );
|
||||||
sqlResultTypeList.add( type );
|
|
||||||
// Generate the select expression.
|
// Generate the select expression.
|
||||||
String text = fromElement.renderIdentifierSelect( size, k );
|
String text = fromElement.renderIdentifierSelect( size, k );
|
||||||
SelectExpressionImpl generatedExpr = ( SelectExpressionImpl ) appender.append( SqlTokenTypes.SELECT_EXPR, text, false );
|
SelectExpressionImpl generatedExpr = ( SelectExpressionImpl ) appender.append( SqlTokenTypes.SELECT_EXPR, text, false );
|
||||||
|
@ -325,7 +309,7 @@ public class SelectClause extends SelectExpressionList {
|
||||||
else {
|
else {
|
||||||
renderNonScalarSelects( selectExpressions, fromClause );
|
renderNonScalarSelects( selectExpressions, fromClause );
|
||||||
}
|
}
|
||||||
finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
|
finishInitialization( queryReturnTypeList );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean VERSION2_SQL = false;
|
public static boolean VERSION2_SQL = false;
|
||||||
|
@ -359,7 +343,7 @@ public class SelectClause extends SelectExpressionList {
|
||||||
private boolean isReturnableEntity(SelectExpression selectExpression) throws SemanticException {
|
private boolean isReturnableEntity(SelectExpression selectExpression) throws SemanticException {
|
||||||
FromElement fromElement = selectExpression.getFromElement();
|
FromElement fromElement = selectExpression.getFromElement();
|
||||||
boolean isFetchOrValueCollection = fromElement != null &&
|
boolean isFetchOrValueCollection = fromElement != null &&
|
||||||
( fromElement.isFetch() || fromElement.isCollectionOfValuesOrComponents() );
|
( fromElement.isFetch() || fromElement.isCollectionOfValuesOrComponents() );
|
||||||
if ( isFetchOrValueCollection ) {
|
if ( isFetchOrValueCollection ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -378,7 +362,7 @@ public class SelectClause extends SelectExpressionList {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initAliases(SelectExpression[] selectExpressions) {
|
private void initAliases(SelectExpression[] selectExpressions) {
|
||||||
if (constructorNode==null) {
|
if ( aggregatedSelectExpression == null ) {
|
||||||
aliases = new String[selectExpressions.length];
|
aliases = new String[selectExpressions.length];
|
||||||
for ( int i=0; i<selectExpressions.length; i++ ) {
|
for ( int i=0; i<selectExpressions.length; i++ ) {
|
||||||
String alias = selectExpressions[i].getAlias();
|
String alias = selectExpressions[i].getAlias();
|
||||||
|
@ -386,7 +370,7 @@ public class SelectClause extends SelectExpressionList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
aliases = constructorNode.getAliases();
|
aliases = aggregatedSelectExpression.getAggregatedAliases();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,7 @@ package org.hibernate.hql.ast.util;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.hql.ast.tree.DisplayableNode;
|
import org.hibernate.hql.ast.tree.DisplayableNode;
|
||||||
|
@ -39,71 +36,62 @@ import org.hibernate.util.StringHelper;
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An 'ASCII art' AST printer for debugging ANTLR grammars.
|
* Utility for generating pretty "ASCII art" representations of syntax trees.
|
||||||
*
|
*
|
||||||
* @author Joshua Davis
|
* @author Joshua Davis
|
||||||
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ASTPrinter {
|
public class ASTPrinter {
|
||||||
private Map tokenTypeNamesByTokenType;
|
private final Map tokenTypeNameCache;
|
||||||
private Class tokenTypeConstants;
|
private final boolean showClassNames;
|
||||||
private boolean showClassNames = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an org.hibernate.hql.antlr.ASTPrinter, given the class that contains the token type
|
* Constructs a printer.
|
||||||
* constants (typically the '{grammar}TokenTypes' interface generated by
|
* <p/>
|
||||||
* ANTLR).
|
* Delegates to {@link #ASTPrinter(Class, boolean)} with {@link #isShowClassNames showClassNames} as <tt>true</tt>
|
||||||
*
|
*
|
||||||
* @param tokenTypeConstants The class with token type constants in it.
|
* @param tokenTypeConstants The token types to use during printing; typically the {vocabulary}TokenTypes.java
|
||||||
|
* interface generated by ANTLR.
|
||||||
*/
|
*/
|
||||||
public ASTPrinter(Class tokenTypeConstants) {
|
public ASTPrinter(Class tokenTypeConstants) {
|
||||||
this.tokenTypeConstants = tokenTypeConstants;
|
this( ASTUtil.generateTokenNameCache( tokenTypeConstants ), true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ASTPrinter(boolean showClassNames) {
|
||||||
|
this( ( Map ) null, showClassNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the node class names will be displayed.
|
* Constructs a printer.
|
||||||
*
|
*
|
||||||
* @return true if the node class names will be displayed.
|
* @param tokenTypeConstants The token types to use during printing; typically the {vocabulary}TokenTypes.java
|
||||||
|
* interface generated by ANTLR.
|
||||||
|
* @param showClassNames Should the AST class names be shown.
|
||||||
|
*/
|
||||||
|
public ASTPrinter(Class tokenTypeConstants, boolean showClassNames) {
|
||||||
|
this( ASTUtil.generateTokenNameCache( tokenTypeConstants ), showClassNames );
|
||||||
|
}
|
||||||
|
|
||||||
|
private ASTPrinter(Map tokenTypeNameCache, boolean showClassNames) {
|
||||||
|
this.tokenTypeNameCache = tokenTypeNameCache;
|
||||||
|
this.showClassNames = showClassNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for property 'showClassNames'.
|
||||||
|
*
|
||||||
|
* @return Value for property 'showClassNames'.
|
||||||
*/
|
*/
|
||||||
public boolean isShowClassNames() {
|
public boolean isShowClassNames() {
|
||||||
return showClassNames;
|
return showClassNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables AST node class name display.
|
* Renders the AST into 'ASCII art' form and returns that string representation.
|
||||||
*
|
*
|
||||||
* @param showClassNames true to enable class name display, false to disable
|
* @param ast The AST to display.
|
||||||
*/
|
|
||||||
public void setShowClassNames(boolean showClassNames) {
|
|
||||||
this.showClassNames = showClassNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the AST in 'ASCII art' tree form to the specified print stream.
|
|
||||||
*
|
|
||||||
* @param ast The AST to print.
|
|
||||||
* @param out The print stream.
|
|
||||||
*/
|
|
||||||
private void showAst(AST ast, PrintStream out) {
|
|
||||||
showAst( ast, new PrintWriter( out ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the AST in 'ASCII art' tree form to the specified print writer.
|
|
||||||
*
|
|
||||||
* @param ast The AST to print.
|
|
||||||
* @param pw The print writer.
|
|
||||||
*/
|
|
||||||
public void showAst(AST ast, PrintWriter pw) {
|
|
||||||
ArrayList parents = new ArrayList();
|
|
||||||
showAst( parents, pw, ast );
|
|
||||||
pw.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the AST in 'ASCII art' tree form into a string.
|
|
||||||
*
|
|
||||||
* @param ast The AST to display.
|
|
||||||
* @param header The header for the display.
|
* @param header The header for the display.
|
||||||
|
*
|
||||||
* @return The AST in 'ASCII art' form, as a string.
|
* @return The AST in 'ASCII art' form, as a string.
|
||||||
*/
|
*/
|
||||||
public String showAsString(AST ast, String header) {
|
public String showAsString(AST ast, String header) {
|
||||||
|
@ -116,53 +104,25 @@ public class ASTPrinter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a single token type name in the specified set of token type constants (interface).
|
* Prints the AST in 'ASCII art' form to the specified print stream.
|
||||||
*
|
*
|
||||||
* @param tokenTypeConstants Token type constants interface (e.g. HqlSqlTokenTypes.class).
|
* @param ast The AST to print.
|
||||||
* @param type The token type ( typically from ast.getType() ).
|
* @param out The print stream to which the AST should be printed.
|
||||||
* @return The token type name, *or* the integer value if the name could not be found for some reason.
|
|
||||||
*/
|
*/
|
||||||
public static String getConstantName(Class tokenTypeConstants, int type) {
|
public void showAst(AST ast, PrintStream out) {
|
||||||
String tokenTypeName = null;
|
showAst( ast, new PrintWriter( out ) );
|
||||||
if ( tokenTypeConstants != null ) {
|
|
||||||
Field[] fields = tokenTypeConstants.getFields();
|
|
||||||
for ( int i = 0; i < fields.length; i++ ) {
|
|
||||||
Field field = fields[i];
|
|
||||||
tokenTypeName = getTokenTypeName( field, type, true );
|
|
||||||
if ( tokenTypeName != null ) {
|
|
||||||
break; // Stop if found.
|
|
||||||
}
|
|
||||||
} // for
|
|
||||||
} // if type constants were provided
|
|
||||||
|
|
||||||
// Use the integer value if no token type name was found
|
|
||||||
if ( tokenTypeName == null ) {
|
|
||||||
tokenTypeName = Integer.toString( type );
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenTypeName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getTokenTypeName(Field field, int type, boolean checkType) {
|
/**
|
||||||
if ( Modifier.isStatic( field.getModifiers() ) ) {
|
* Prints the AST in 'ASCII art' tree form to the specified print writer.
|
||||||
try {
|
*
|
||||||
Object value = field.get( null );
|
* @param ast The AST to print.
|
||||||
if ( !checkType ) {
|
* @param pw The print writer to which the AST should be written.
|
||||||
return field.getName();
|
*/
|
||||||
}
|
public void showAst(AST ast, PrintWriter pw) {
|
||||||
else if ( value instanceof Integer ) {
|
ArrayList parents = new ArrayList();
|
||||||
Integer integer = ( Integer ) value;
|
showAst( parents, pw, ast );
|
||||||
if ( integer.intValue() == type ) {
|
pw.flush();
|
||||||
return field.getName();
|
|
||||||
}
|
|
||||||
} // if value is an integer
|
|
||||||
} // try
|
|
||||||
catch ( IllegalArgumentException ignore ) {
|
|
||||||
}
|
|
||||||
catch ( IllegalAccessException ignore ) {
|
|
||||||
}
|
|
||||||
} // if the field is static
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,33 +132,16 @@ public class ASTPrinter {
|
||||||
* @return String - The token type name from the token type constant class,
|
* @return String - The token type name from the token type constant class,
|
||||||
* or just the integer as a string if none exists.
|
* or just the integer as a string if none exists.
|
||||||
*/
|
*/
|
||||||
private String getTokenTypeName(int type) {
|
public String getTokenTypeName(int type) {
|
||||||
// If the class with the constants in it was not supplied, just
|
final Integer typeInteger = new Integer( type );
|
||||||
// use the integer token type as the token type name.
|
String value = null;
|
||||||
if ( tokenTypeConstants == null ) {
|
if ( tokenTypeNameCache != null ) {
|
||||||
return Integer.toString( type );
|
value = ( String ) tokenTypeNameCache.get( typeInteger );
|
||||||
}
|
}
|
||||||
|
if ( value == null ) {
|
||||||
// Otherwise, create a type id -> name map from the class if it
|
value = typeInteger.toString();
|
||||||
// hasn't already been created.
|
}
|
||||||
if ( tokenTypeNamesByTokenType == null ) {
|
return value;
|
||||||
Field[] fields = tokenTypeConstants.getFields();
|
|
||||||
tokenTypeNamesByTokenType = new HashMap();
|
|
||||||
String tokenTypeName = null;
|
|
||||||
for ( int i = 0; i < fields.length; i++ ) {
|
|
||||||
Field field = fields[i];
|
|
||||||
tokenTypeName = getTokenTypeName( field, type, false );
|
|
||||||
if ( tokenTypeName != null ) {
|
|
||||||
try {
|
|
||||||
tokenTypeNamesByTokenType.put( field.get( null ), field.getName() );
|
|
||||||
}
|
|
||||||
catch ( IllegalAccessException ignore ) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // for
|
|
||||||
} // if the map hasn't been created.
|
|
||||||
|
|
||||||
return ( String ) tokenTypeNamesByTokenType.get( new Integer( type ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showAst(ArrayList parents, PrintWriter pw, AST ast) {
|
private void showAst(ArrayList parents, PrintWriter pw, AST ast) {
|
||||||
|
@ -242,7 +185,7 @@ public class ASTPrinter {
|
||||||
|
|
||||||
public String nodeToString(AST ast, boolean showClassName) {
|
public String nodeToString(AST ast, boolean showClassName) {
|
||||||
if ( ast == null ) {
|
if ( ast == null ) {
|
||||||
return "{null}";
|
return "{node:null}";
|
||||||
}
|
}
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append( "[" ).append( getTokenTypeName( ast.getType() ) ).append( "] " );
|
buf.append( "[" ).append( getTokenTypeName( ast.getType() ) ).append( "] " );
|
||||||
|
@ -252,15 +195,17 @@ public class ASTPrinter {
|
||||||
|
|
||||||
buf.append( "'" );
|
buf.append( "'" );
|
||||||
String text = ast.getText();
|
String text = ast.getText();
|
||||||
appendEscapedMultibyteChars(text, buf);
|
if ( text == null ) {
|
||||||
|
text = "{text:null}";
|
||||||
|
}
|
||||||
|
appendEscapedMultibyteChars(text, buf);
|
||||||
buf.append( "'" );
|
buf.append( "'" );
|
||||||
if ( ast instanceof DisplayableNode ) {
|
if ( ast instanceof DisplayableNode ) {
|
||||||
DisplayableNode displayableNode = ( DisplayableNode ) ast;
|
DisplayableNode displayableNode = ( DisplayableNode ) ast;
|
||||||
// Add a space before the display text.
|
// Add a space before the display text.
|
||||||
buf.append( " " ).append( displayableNode.getDisplayText() );
|
buf.append( " " ).append( displayableNode.getDisplayText() );
|
||||||
}
|
}
|
||||||
String s = buf.toString();
|
return buf.toString();
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void appendEscapedMultibyteChars(String text, StringBuffer buf) {
|
public static void appendEscapedMultibyteChars(String text, StringBuffer buf) {
|
||||||
|
@ -276,10 +221,9 @@ public class ASTPrinter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String escapeMultibyteChars(String text)
|
public static String escapeMultibyteChars(String text) {
|
||||||
{
|
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
appendEscapedMultibyteChars(text,buf);
|
appendEscapedMultibyteChars(text,buf);
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,10 @@ package org.hibernate.hql.ast.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import antlr.ASTFactory;
|
import antlr.ASTFactory;
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
|
@ -35,46 +39,62 @@ import antlr.collections.impl.ASTArray;
|
||||||
* Provides utility methods for AST traversal and manipulation.
|
* Provides utility methods for AST traversal and manipulation.
|
||||||
*
|
*
|
||||||
* @author Joshua Davis
|
* @author Joshua Davis
|
||||||
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public final class ASTUtil {
|
public final class ASTUtil {
|
||||||
/**
|
/**
|
||||||
* Private empty constructor.
|
* Disallow instantiation.
|
||||||
* (or else checkstyle says: 'warning: Utility classes should not have a public or default constructor.')
|
|
||||||
*
|
*
|
||||||
* @deprecated (tell clover to ignore this)
|
* @deprecated (tellclovertoignorethis)
|
||||||
*/
|
*/
|
||||||
private ASTUtil() {
|
private ASTUtil() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a single node AST.
|
* Creates a single node AST.
|
||||||
|
* <p/>
|
||||||
|
* TODO : this is silly, remove it...
|
||||||
*
|
*
|
||||||
* @param astFactory The factory.
|
* @param astFactory The factory.
|
||||||
* @param type The node type.
|
* @param type The node type.
|
||||||
* @param text The node text.
|
* @param text The node text.
|
||||||
|
*
|
||||||
* @return AST - A single node tree.
|
* @return AST - A single node tree.
|
||||||
|
*
|
||||||
|
* @deprecated silly
|
||||||
*/
|
*/
|
||||||
public static AST create(ASTFactory astFactory, int type, String text) {
|
public static AST create(ASTFactory astFactory, int type, String text) {
|
||||||
AST node = astFactory.create( type, text );
|
return astFactory.create( type, text );
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a single node AST as a sibling.
|
* Creates a single node AST as a sibling of the passed prevSibling,
|
||||||
|
* taking care to reorganize the tree correctly to account for this
|
||||||
|
* newly created node.
|
||||||
*
|
*
|
||||||
* @param astFactory The factory.
|
* @param astFactory The factory.
|
||||||
* @param type The node type.
|
* @param type The node type.
|
||||||
* @param text The node text.
|
* @param text The node text.
|
||||||
* @param prevSibling The previous sibling.
|
* @param prevSibling The previous sibling.
|
||||||
* @return AST - A single node tree.
|
*
|
||||||
|
* @return The created AST node.
|
||||||
*/
|
*/
|
||||||
public static AST createSibling(ASTFactory astFactory, int type, String text, AST prevSibling) {
|
public static AST createSibling(ASTFactory astFactory, int type, String text, AST prevSibling) {
|
||||||
AST node = astFactory.create( type, text );
|
AST node = astFactory.create( type, text );
|
||||||
node.setNextSibling( prevSibling.getNextSibling() );
|
return insertSibling( node, prevSibling );
|
||||||
prevSibling.setNextSibling( node );
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a node into a child subtree as a particularly positioned
|
||||||
|
* sibling taking care to properly reorganize the tree to account for this
|
||||||
|
* new addition.
|
||||||
|
*
|
||||||
|
* @param node The node to insert
|
||||||
|
* @param prevSibling The previous node at the sibling position
|
||||||
|
* where we want this node inserted.
|
||||||
|
*
|
||||||
|
* @return The return is the same as the node parameter passed in.
|
||||||
|
*/
|
||||||
public static AST insertSibling(AST node, AST prevSibling) {
|
public static AST insertSibling(AST node, AST prevSibling) {
|
||||||
node.setNextSibling( prevSibling.getNextSibling() );
|
node.setNextSibling( prevSibling.getNextSibling() );
|
||||||
prevSibling.setNextSibling( node );
|
prevSibling.setNextSibling( node );
|
||||||
|
@ -85,11 +105,12 @@ public final class ASTUtil {
|
||||||
* Creates a 'binary operator' subtree, given the information about the
|
* Creates a 'binary operator' subtree, given the information about the
|
||||||
* parent and the two child nodex.
|
* parent and the two child nodex.
|
||||||
*
|
*
|
||||||
* @param factory The AST factory.
|
* @param factory The AST factory.
|
||||||
* @param parentType The type of the parent node.
|
* @param parentType The type of the parent node.
|
||||||
* @param parentText The text of the parent node.
|
* @param parentText The text of the parent node.
|
||||||
* @param child1 The first child.
|
* @param child1 The first child.
|
||||||
* @param child2 The second child.
|
* @param child2 The second child.
|
||||||
|
*
|
||||||
* @return AST - A new sub-tree of the form "(parent child1 child2)"
|
* @return AST - A new sub-tree of the form "(parent child1 child2)"
|
||||||
*/
|
*/
|
||||||
public static AST createBinarySubtree(ASTFactory factory, int parentType, String parentText, AST child1, AST child2) {
|
public static AST createBinarySubtree(ASTFactory factory, int parentType, String parentText, AST child1, AST child2) {
|
||||||
|
@ -102,10 +123,11 @@ public final class ASTUtil {
|
||||||
* Creates a single parent of the specified child (i.e. a 'unary operator'
|
* Creates a single parent of the specified child (i.e. a 'unary operator'
|
||||||
* subtree).
|
* subtree).
|
||||||
*
|
*
|
||||||
* @param factory The AST factory.
|
* @param factory The AST factory.
|
||||||
* @param parentType The type of the parent node.
|
* @param parentType The type of the parent node.
|
||||||
* @param parentText The text of the parent node.
|
* @param parentText The text of the parent node.
|
||||||
* @param child The child.
|
* @param child The child.
|
||||||
|
*
|
||||||
* @return AST - A new sub-tree of the form "(parent child)"
|
* @return AST - A new sub-tree of the form "(parent child)"
|
||||||
*/
|
*/
|
||||||
public static AST createParent(ASTFactory factory, int parentType, String parentText, AST child) {
|
public static AST createParent(ASTFactory factory, int parentType, String parentText, AST child) {
|
||||||
|
@ -126,100 +148,6 @@ public final class ASTUtil {
|
||||||
return array[0];
|
return array[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the first node of the specified type in the chain of children.
|
|
||||||
*
|
|
||||||
* @param parent The parent
|
|
||||||
* @param type The type to find.
|
|
||||||
* @return The first node of the specified type, or null if not found.
|
|
||||||
*/
|
|
||||||
public static AST findTypeInChildren(AST parent, int type) {
|
|
||||||
AST n = parent.getFirstChild();
|
|
||||||
while ( n != null && n.getType() != type ) {
|
|
||||||
n = n.getNextSibling();
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last direct child of 'n'.
|
|
||||||
*
|
|
||||||
* @param n The parent
|
|
||||||
* @return The last direct child of 'n'.
|
|
||||||
*/
|
|
||||||
public static AST getLastChild(AST n) {
|
|
||||||
return getLastSibling( n.getFirstChild() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last sibling of 'a'.
|
|
||||||
*
|
|
||||||
* @param a The sibling.
|
|
||||||
* @return The last sibling of 'a'.
|
|
||||||
*/
|
|
||||||
private static AST getLastSibling(AST a) {
|
|
||||||
AST last = null;
|
|
||||||
while ( a != null ) {
|
|
||||||
last = a;
|
|
||||||
a = a.getNextSibling();
|
|
||||||
}
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the 'list' representation with some brackets around it for debugging.
|
|
||||||
*
|
|
||||||
* @param n The tree.
|
|
||||||
* @return The list representation of the tree.
|
|
||||||
*/
|
|
||||||
public static String getDebugString(AST n) {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
buf.append( "[ " );
|
|
||||||
buf.append( ( n == null ) ? "{null}" : n.toStringTree() );
|
|
||||||
buf.append( " ]" );
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the previous sibling in the parent for the given child.
|
|
||||||
*
|
|
||||||
* @param parent the parent node
|
|
||||||
* @param child the child to find the previous sibling of
|
|
||||||
* @return the previous sibling of the child
|
|
||||||
*/
|
|
||||||
public static AST findPreviousSibling(AST parent, AST child) {
|
|
||||||
AST prev = null;
|
|
||||||
AST n = parent.getFirstChild();
|
|
||||||
while ( n != null ) {
|
|
||||||
if ( n == child ) {
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
prev = n;
|
|
||||||
n = n.getNextSibling();
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException( "Child not found in parent!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a given node (test) is a direct (throtle to one level down)
|
|
||||||
* child of another given node (fixture).
|
|
||||||
*
|
|
||||||
* @param fixture The node against which to testto be checked for children.
|
|
||||||
* @param test The node to be tested as being a child of the parent.
|
|
||||||
* @return True if test is contained in the fixtures's direct children;
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isDirectChild(AST fixture, AST test) {
|
|
||||||
AST n = fixture.getFirstChild();
|
|
||||||
while ( n != null ) {
|
|
||||||
if ( n == test ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
n = n.getNextSibling();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a given node (test) is contained anywhere in the subtree
|
* Determine if a given node (test) is contained anywhere in the subtree
|
||||||
* of another given node (fixture).
|
* of another given node (fixture).
|
||||||
|
@ -242,11 +170,90 @@ public final class ASTUtil {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the first node of the specified type in the chain of children.
|
||||||
|
*
|
||||||
|
* @param parent The parent
|
||||||
|
* @param type The type to find.
|
||||||
|
*
|
||||||
|
* @return The first node of the specified type, or null if not found.
|
||||||
|
*/
|
||||||
|
public static AST findTypeInChildren(AST parent, int type) {
|
||||||
|
AST n = parent.getFirstChild();
|
||||||
|
while ( n != null && n.getType() != type ) {
|
||||||
|
n = n.getNextSibling();
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last direct child of 'n'.
|
||||||
|
*
|
||||||
|
* @param n The parent
|
||||||
|
*
|
||||||
|
* @return The last direct child of 'n'.
|
||||||
|
*/
|
||||||
|
public static AST getLastChild(AST n) {
|
||||||
|
return getLastSibling( n.getFirstChild() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last sibling of 'a'.
|
||||||
|
*
|
||||||
|
* @param a The sibling.
|
||||||
|
*
|
||||||
|
* @return The last sibling of 'a'.
|
||||||
|
*/
|
||||||
|
private static AST getLastSibling(AST a) {
|
||||||
|
AST last = null;
|
||||||
|
while ( a != null ) {
|
||||||
|
last = a;
|
||||||
|
a = a.getNextSibling();
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 'list' representation with some brackets around it for debugging.
|
||||||
|
*
|
||||||
|
* @param n The tree.
|
||||||
|
*
|
||||||
|
* @return The list representation of the tree.
|
||||||
|
*/
|
||||||
|
public static String getDebugString(AST n) {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append( "[ " );
|
||||||
|
buf.append( ( n == null ) ? "{null}" : n.toStringTree() );
|
||||||
|
buf.append( " ]" );
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the previous sibling in the parent for the given child.
|
||||||
|
*
|
||||||
|
* @param parent the parent node
|
||||||
|
* @param child the child to find the previous sibling of
|
||||||
|
*
|
||||||
|
* @return the previous sibling of the child
|
||||||
|
*/
|
||||||
|
public static AST findPreviousSibling(AST parent, AST child) {
|
||||||
|
AST prev = null;
|
||||||
|
AST n = parent.getFirstChild();
|
||||||
|
while ( n != null ) {
|
||||||
|
if ( n == child ) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
prev = n;
|
||||||
|
n = n.getNextSibling();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException( "Child not found in parent!" );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the child node a sibling of the parent, reconnecting all siblings.
|
* Makes the child node a sibling of the parent, reconnecting all siblings.
|
||||||
*
|
*
|
||||||
* @param parent the parent
|
* @param parent the parent
|
||||||
* @param child the child
|
* @param child the child
|
||||||
*/
|
*/
|
||||||
public static void makeSiblingOfParent(AST parent, AST child) {
|
public static void makeSiblingOfParent(AST parent, AST child) {
|
||||||
AST prev = findPreviousSibling( parent, child );
|
AST prev = findPreviousSibling( parent, child );
|
||||||
|
@ -295,7 +302,7 @@ public final class ASTUtil {
|
||||||
* Inserts the child as the first child of the parent, all other children are shifted over to the 'right'.
|
* Inserts the child as the first child of the parent, all other children are shifted over to the 'right'.
|
||||||
*
|
*
|
||||||
* @param parent the parent
|
* @param parent the parent
|
||||||
* @param child the new first child
|
* @param child the new first child
|
||||||
*/
|
*/
|
||||||
public static void insertChild(AST parent, AST child) {
|
public static void insertChild(AST parent, AST child) {
|
||||||
if ( parent.getFirstChild() == null ) {
|
if ( parent.getFirstChild() == null ) {
|
||||||
|
@ -308,6 +315,13 @@ public final class ASTUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ASTArray createAstArray(ASTFactory factory, int size, int parentType, String parentText, AST child1) {
|
||||||
|
ASTArray array = new ASTArray( size );
|
||||||
|
array.add( factory.create( parentType, parentText ) );
|
||||||
|
array.add( child1 );
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters nodes out of a tree.
|
* Filters nodes out of a tree.
|
||||||
*/
|
*/
|
||||||
|
@ -316,6 +330,7 @@ public final class ASTUtil {
|
||||||
* Returns true if the node should be filtered out.
|
* Returns true if the node should be filtered out.
|
||||||
*
|
*
|
||||||
* @param n The node.
|
* @param n The node.
|
||||||
|
*
|
||||||
* @return true if the node should be filtered out, false to keep the node.
|
* @return true if the node should be filtered out, false to keep the node.
|
||||||
*/
|
*/
|
||||||
boolean exclude(AST n);
|
boolean exclude(AST n);
|
||||||
|
@ -332,17 +347,7 @@ public final class ASTUtil {
|
||||||
public abstract boolean include(AST node);
|
public abstract boolean include(AST node);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ASTArray createAstArray(ASTFactory factory, int size, int parentType, String parentText, AST child1) {
|
|
||||||
ASTArray array = new ASTArray( size );
|
|
||||||
array.add( factory.create( parentType, parentText ) );
|
|
||||||
array.add( child1 );
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List collectChildren(AST root, FilterPredicate predicate) {
|
public static List collectChildren(AST root, FilterPredicate predicate) {
|
||||||
// List children = new ArrayList();
|
|
||||||
// collectChildren( children, root, predicate );
|
|
||||||
// return children;
|
|
||||||
return new CollectingNodeVisitor( predicate ).collect( root );
|
return new CollectingNodeVisitor( predicate ).collect( root );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,13 +376,89 @@ public final class ASTUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void collectChildren(List children, AST root, FilterPredicate predicate) {
|
/**
|
||||||
for ( AST n = root.getFirstChild(); n != null; n = n.getNextSibling() ) {
|
* Method to generate a map of token type names, keyed by their token type values.
|
||||||
if ( predicate == null || !predicate.exclude( n ) ) {
|
*
|
||||||
children.add( n );
|
* @param tokenTypeInterface The *TokenTypes interface (or implementor of said interface).
|
||||||
|
* @return The generated map.
|
||||||
|
*/
|
||||||
|
public static Map generateTokenNameCache(Class tokenTypeInterface) {
|
||||||
|
final Field[] fields = tokenTypeInterface.getFields();
|
||||||
|
Map cache = new HashMap( (int)( fields.length * .75 ) + 1 );
|
||||||
|
for ( int i = 0; i < fields.length; i++ ) {
|
||||||
|
final Field field = fields[i];
|
||||||
|
if ( Modifier.isStatic( field.getModifiers() ) ) {
|
||||||
|
try {
|
||||||
|
cache.put( field.get( null ), field.getName() );
|
||||||
|
}
|
||||||
|
catch ( Throwable ignore ) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
collectChildren( children, n, predicate );
|
|
||||||
}
|
}
|
||||||
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of a constant defined on the given class which has the given value.
|
||||||
|
* <p/>
|
||||||
|
* Note, if multiple constants have this value, the first will be returned which is known to be different
|
||||||
|
* on different JVM implementations.
|
||||||
|
*
|
||||||
|
* @param owner The class which defines the constant
|
||||||
|
* @param value The value of the constant.
|
||||||
|
*
|
||||||
|
* @return The token type name, *or* the integer value if the name could not be found.
|
||||||
|
*
|
||||||
|
* @deprecated Use #getTokenTypeName instead
|
||||||
|
*/
|
||||||
|
public static String getConstantName(Class owner, int value) {
|
||||||
|
return getTokenTypeName( owner, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intended to retrieve the name of an AST token type based on the token type interface. However, this
|
||||||
|
* method can be used to look up the name of any constant defined on a class/interface based on the constant value.
|
||||||
|
* Note that if multiple constants have this value, the first will be returned which is known to be different
|
||||||
|
* on different JVM implementations.
|
||||||
|
*
|
||||||
|
* @param tokenTypeInterface The *TokenTypes interface (or one of its implementors).
|
||||||
|
* @param tokenType The token type value.
|
||||||
|
*
|
||||||
|
* @return The corresponding name.
|
||||||
|
*/
|
||||||
|
public static String getTokenTypeName(Class tokenTypeInterface, int tokenType) {
|
||||||
|
String tokenTypeName = Integer.toString( tokenType );
|
||||||
|
if ( tokenTypeInterface != null ) {
|
||||||
|
Field[] fields = tokenTypeInterface.getFields();
|
||||||
|
for ( int i = 0; i < fields.length; i++ ) {
|
||||||
|
final Integer fieldValue = extractIntegerValue( fields[i] );
|
||||||
|
if ( fieldValue != null && fieldValue.intValue() == tokenType ) {
|
||||||
|
tokenTypeName = fields[i].getName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokenTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Integer extractIntegerValue(Field field) {
|
||||||
|
Integer rtn = null;
|
||||||
|
try {
|
||||||
|
Object value = field.get( null );
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
rtn = ( Integer ) value;
|
||||||
|
}
|
||||||
|
else if ( value instanceof Short ) {
|
||||||
|
rtn = new Integer( ( ( Short ) value ).intValue() );
|
||||||
|
}
|
||||||
|
else if ( value instanceof Long ) {
|
||||||
|
if ( ( ( Long ) value ).longValue() <= Integer.MAX_VALUE ) {
|
||||||
|
rtn = new Integer( ( ( Long ) value ).intValue() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( IllegalAccessException ignore ) {
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.hibernate.hql.ast.QueryTranslatorImpl;
|
||||||
import org.hibernate.hql.ast.tree.FromElement;
|
import org.hibernate.hql.ast.tree.FromElement;
|
||||||
import org.hibernate.hql.ast.tree.SelectClause;
|
import org.hibernate.hql.ast.tree.SelectClause;
|
||||||
import org.hibernate.hql.ast.tree.QueryNode;
|
import org.hibernate.hql.ast.tree.QueryNode;
|
||||||
|
import org.hibernate.hql.ast.tree.AggregatedSelectExpression;
|
||||||
import org.hibernate.impl.IteratorImpl;
|
import org.hibernate.impl.IteratorImpl;
|
||||||
import org.hibernate.loader.BasicLoader;
|
import org.hibernate.loader.BasicLoader;
|
||||||
import org.hibernate.param.ParameterSpecification;
|
import org.hibernate.param.ParameterSpecification;
|
||||||
|
@ -96,7 +97,7 @@ public class QueryLoader extends BasicLoader {
|
||||||
|
|
||||||
private int selectLength;
|
private int selectLength;
|
||||||
|
|
||||||
private ResultTransformer selectNewTransformer;
|
private ResultTransformer implicitResultTransformer;
|
||||||
private String[] queryReturnAliases;
|
private String[] queryReturnAliases;
|
||||||
|
|
||||||
private LockMode[] defaultLockModes;
|
private LockMode[] defaultLockModes;
|
||||||
|
@ -128,10 +129,10 @@ public class QueryLoader extends BasicLoader {
|
||||||
//sqlResultTypes = selectClause.getSqlResultTypes();
|
//sqlResultTypes = selectClause.getSqlResultTypes();
|
||||||
queryReturnTypes = selectClause.getQueryReturnTypes();
|
queryReturnTypes = selectClause.getQueryReturnTypes();
|
||||||
|
|
||||||
selectNewTransformer = HolderInstantiator.createSelectNewTransformer(
|
AggregatedSelectExpression aggregatedSelectExpression = selectClause.getAggregatedSelectExpression();
|
||||||
selectClause.getConstructor(),
|
implicitResultTransformer = aggregatedSelectExpression == null
|
||||||
selectClause.isMap(),
|
? null
|
||||||
selectClause.isList());
|
: aggregatedSelectExpression.getResultTransformer();
|
||||||
queryReturnAliases = selectClause.getQueryReturnAliases();
|
queryReturnAliases = selectClause.getQueryReturnAliases();
|
||||||
|
|
||||||
List collectionFromElements = selectClause.getCollectionFromElements();
|
List collectionFromElements = selectClause.getCollectionFromElements();
|
||||||
|
@ -341,7 +342,7 @@ public class QueryLoader extends BasicLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasSelectNew() {
|
private boolean hasSelectNew() {
|
||||||
return selectNewTransformer!=null;
|
return implicitResultTransformer != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
|
protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
|
||||||
|
@ -374,7 +375,7 @@ public class QueryLoader extends BasicLoader {
|
||||||
|
|
||||||
protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
|
protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
|
||||||
// meant to handle dynamic instantiation queries...
|
// meant to handle dynamic instantiation queries...
|
||||||
HolderInstantiator holderInstantiator = HolderInstantiator.getHolderInstantiator(selectNewTransformer, resultTransformer, queryReturnAliases);
|
HolderInstantiator holderInstantiator = buildHolderInstantiator( resultTransformer );
|
||||||
if ( holderInstantiator.isRequired() ) {
|
if ( holderInstantiator.isRequired() ) {
|
||||||
for ( int i = 0; i < results.size(); i++ ) {
|
for ( int i = 0; i < results.size(); i++ ) {
|
||||||
Object[] row = ( Object[] ) results.get( i );
|
Object[] row = ( Object[] ) results.get( i );
|
||||||
|
@ -382,16 +383,25 @@ public class QueryLoader extends BasicLoader {
|
||||||
results.set( i, result );
|
results.set( i, result );
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!hasSelectNew() && resultTransformer!=null) {
|
if ( !hasSelectNew() && resultTransformer != null ) {
|
||||||
return resultTransformer.transformList(results);
|
return resultTransformer.transformList(results);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HolderInstantiator buildHolderInstantiator(ResultTransformer queryLocalResultTransformer) {
|
||||||
|
return HolderInstantiator.getHolderInstantiator(
|
||||||
|
implicitResultTransformer,
|
||||||
|
queryLocalResultTransformer,
|
||||||
|
queryReturnAliases
|
||||||
|
);
|
||||||
|
}
|
||||||
// --- Query translator methods ---
|
// --- Query translator methods ---
|
||||||
|
|
||||||
public List list(
|
public List list(
|
||||||
|
@ -418,10 +428,8 @@ public class QueryLoader extends BasicLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
|
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
|
||||||
|
if ( queryParameters.isCallable() ) {
|
||||||
if(queryParameters.isCallable()) {
|
|
||||||
throw new QueryException("iterate() not supported for callable statements");
|
throw new QueryException("iterate() not supported for callable statements");
|
||||||
}
|
}
|
||||||
final ResultSet rs = getResultSet(st, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session);
|
final ResultSet rs = getResultSet(st, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session);
|
||||||
|
@ -431,8 +439,8 @@ public class QueryLoader extends BasicLoader {
|
||||||
session,
|
session,
|
||||||
queryReturnTypes,
|
queryReturnTypes,
|
||||||
queryTranslator.getColumnNames(),
|
queryTranslator.getColumnNames(),
|
||||||
HolderInstantiator.getHolderInstantiator(selectNewTransformer, queryParameters.getResultTransformer(), queryReturnAliases)
|
buildHolderInstantiator( queryParameters.getResultTransformer() )
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( stats ) {
|
if ( stats ) {
|
||||||
session.getFactory().getStatisticsImplementor().queryExecuted(
|
session.getFactory().getStatisticsImplementor().queryExecuted(
|
||||||
|
@ -461,7 +469,12 @@ public class QueryLoader extends BasicLoader {
|
||||||
final QueryParameters queryParameters,
|
final QueryParameters queryParameters,
|
||||||
final SessionImplementor session) throws HibernateException {
|
final SessionImplementor session) throws HibernateException {
|
||||||
checkQuery( queryParameters );
|
checkQuery( queryParameters );
|
||||||
return scroll( queryParameters, queryReturnTypes, HolderInstantiator.getHolderInstantiator(selectNewTransformer, queryParameters.getResultTransformer(), queryReturnAliases), session );
|
return scroll(
|
||||||
|
queryParameters,
|
||||||
|
queryReturnTypes,
|
||||||
|
buildHolderInstantiator( queryParameters.getResultTransformer() ),
|
||||||
|
session
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Implementation private methods --
|
// -- Implementation private methods --
|
||||||
|
|
|
@ -99,6 +99,7 @@ import org.hibernate.sql.SelectFragment;
|
||||||
import org.hibernate.sql.SimpleSelect;
|
import org.hibernate.sql.SimpleSelect;
|
||||||
import org.hibernate.sql.Template;
|
import org.hibernate.sql.Template;
|
||||||
import org.hibernate.sql.Update;
|
import org.hibernate.sql.Update;
|
||||||
|
import org.hibernate.sql.AliasGenerator;
|
||||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||||
import org.hibernate.tuple.Tuplizer;
|
import org.hibernate.tuple.Tuplizer;
|
||||||
|
@ -982,8 +983,14 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String propertySelectFragment(String name, String suffix, boolean allProperties) {
|
public String propertySelectFragment(String tableAlias, String suffix, boolean allProperties) {
|
||||||
|
return propertySelectFragmentFragment( tableAlias, suffix, allProperties ).toFragmentString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectFragment propertySelectFragmentFragment(
|
||||||
|
String tableAlias,
|
||||||
|
String suffix,
|
||||||
|
boolean allProperties) {
|
||||||
SelectFragment select = new SelectFragment()
|
SelectFragment select = new SelectFragment()
|
||||||
.setSuffix( suffix )
|
.setSuffix( suffix )
|
||||||
.setUsedAliases( getIdentifierAliases() );
|
.setUsedAliases( getIdentifierAliases() );
|
||||||
|
@ -996,7 +1003,7 @@ public abstract class AbstractEntityPersister
|
||||||
!isSubclassTableSequentialSelect( columnTableNumbers[i] ) &&
|
!isSubclassTableSequentialSelect( columnTableNumbers[i] ) &&
|
||||||
subclassColumnSelectableClosure[i];
|
subclassColumnSelectableClosure[i];
|
||||||
if ( selectable ) {
|
if ( selectable ) {
|
||||||
String subalias = generateTableAlias( name, columnTableNumbers[i] );
|
String subalias = generateTableAlias( tableAlias, columnTableNumbers[i] );
|
||||||
select.addColumn( subalias, columns[i], columnAliases[i] );
|
select.addColumn( subalias, columns[i], columnAliases[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1008,20 +1015,20 @@ public abstract class AbstractEntityPersister
|
||||||
boolean selectable = ( allProperties || !subclassFormulaLazyClosure[i] )
|
boolean selectable = ( allProperties || !subclassFormulaLazyClosure[i] )
|
||||||
&& !isSubclassTableSequentialSelect( formulaTableNumbers[i] );
|
&& !isSubclassTableSequentialSelect( formulaTableNumbers[i] );
|
||||||
if ( selectable ) {
|
if ( selectable ) {
|
||||||
String subalias = generateTableAlias( name, formulaTableNumbers[i] );
|
String subalias = generateTableAlias( tableAlias, formulaTableNumbers[i] );
|
||||||
select.addFormula( subalias, formulaTemplates[i], formulaAliases[i] );
|
select.addFormula( subalias, formulaTemplates[i], formulaAliases[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( entityMetamodel.hasSubclasses() ) {
|
if ( entityMetamodel.hasSubclasses() ) {
|
||||||
addDiscriminatorToSelect( select, name, suffix );
|
addDiscriminatorToSelect( select, tableAlias, suffix );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hasRowId() ) {
|
if ( hasRowId() ) {
|
||||||
select.addColumn( name, rowIdName, ROWID_ALIAS );
|
select.addColumn( tableAlias, rowIdName, ROWID_ALIAS );
|
||||||
}
|
}
|
||||||
|
|
||||||
return select.toFragmentString();
|
return select;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session)
|
public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session)
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.persister.entity;
|
package org.hibernate.persister.entity;
|
||||||
|
|
||||||
|
import org.hibernate.sql.SelectFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends the generic <tt>EntityPersister</tt> contract to add
|
* Extends the generic <tt>EntityPersister</tt> contract to add
|
||||||
* operations required by the Hibernate Query Language
|
* operations required by the Hibernate Query Language
|
||||||
|
@ -60,6 +62,7 @@ public interface Queryable extends Loadable, PropertyMapping, Joinable {
|
||||||
*/
|
*/
|
||||||
public String propertySelectFragment(String alias, String suffix, boolean allProperties);
|
public String propertySelectFragment(String alias, String suffix, boolean allProperties);
|
||||||
|
|
||||||
|
public SelectFragment propertySelectFragmentFragment(String alias, String suffix, boolean allProperties);
|
||||||
/**
|
/**
|
||||||
* Get the names of columns used to persist the identifier
|
* Get the names of columns used to persist the identifier
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.sql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface AliasGenerator {
|
||||||
|
public String generateAlias(String sqlExpression);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.sql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface SelectExpression {
|
||||||
|
public String getExpression();
|
||||||
|
public String getAlias();
|
||||||
|
}
|
|
@ -46,7 +46,15 @@ public class SelectFragment {
|
||||||
private String[] usedAliases;
|
private String[] usedAliases;
|
||||||
|
|
||||||
public SelectFragment() {}
|
public SelectFragment() {}
|
||||||
|
|
||||||
|
public List getColumns() {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtraSelectList() {
|
||||||
|
return extraSelectList;
|
||||||
|
}
|
||||||
|
|
||||||
public SelectFragment setUsedAliases(String[] aliases) {
|
public SelectFragment setUsedAliases(String[] aliases) {
|
||||||
usedAliases = aliases;
|
usedAliases = aliases;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import antlr.collections.AST;
|
||||||
|
|
||||||
import org.hibernate.sql.Template;
|
import org.hibernate.sql.Template;
|
||||||
import org.hibernate.dialect.function.SQLFunction;
|
import org.hibernate.dialect.function.SQLFunction;
|
||||||
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -52,6 +53,28 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private int traceDepth = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public void traceIn(String ruleName) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void traceOut(String ruleName) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,13 +26,50 @@ package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
|
|
||||||
|
import org.hibernate.util.StringHelper;
|
||||||
|
import org.hibernate.hql.ast.util.ASTPrinter;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO : javadoc
|
* TODO : javadoc
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
|
public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger( OrderByFragmentRenderer.class );
|
||||||
|
private static final ASTPrinter printer = new ASTPrinter( GeneratedOrderByFragmentRendererTokenTypes.class );
|
||||||
|
|
||||||
protected void out(AST ast) {
|
protected void out(AST ast) {
|
||||||
out( ( ( Node ) ast ).getRenderableText() );
|
out( ( ( Node ) ast ).getRenderableText() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private int traceDepth = 0;
|
||||||
|
|
||||||
|
public void traceIn(String ruleName, AST tree) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
||||||
|
String traceText = ruleName + " (" + buildTraceNodeName(tree) + ")";
|
||||||
|
log.trace( prefix + traceText );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildTraceNodeName(AST tree) {
|
||||||
|
return tree == null
|
||||||
|
? "???"
|
||||||
|
: tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void traceOut(String ruleName, AST tree) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
||||||
|
log.trace( prefix + ruleName );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ public final class ArrayHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] toStringArray(Collection coll) {
|
public static String[] toStringArray(Collection coll) {
|
||||||
return (String[]) coll.toArray(EMPTY_STRING_ARRAY);
|
return (String[]) coll.toArray( new String[coll.size()] );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[][] to2DStringArray(Collection coll) {
|
public static String[][] to2DStringArray(Collection coll) {
|
||||||
|
@ -96,7 +96,7 @@ public final class ArrayHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type[] toTypeArray(Collection coll) {
|
public static Type[] toTypeArray(Collection coll) {
|
||||||
return (Type[]) coll.toArray(EMPTY_TYPE_ARRAY);
|
return (Type[]) coll.toArray( new Type[coll.size()] );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int[] toIntArray(Collection coll) {
|
public static int[] toIntArray(Collection coll) {
|
||||||
|
@ -136,17 +136,13 @@ public final class ArrayHelper {
|
||||||
|
|
||||||
public static String[] slice(String[] strings, int begin, int length) {
|
public static String[] slice(String[] strings, int begin, int length) {
|
||||||
String[] result = new String[length];
|
String[] result = new String[length];
|
||||||
for ( int i=0; i<length; i++ ) {
|
System.arraycopy( strings, begin, result, 0, length );
|
||||||
result[i] = strings[begin+i];
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] slice(Object[] objects, int begin, int length) {
|
public static Object[] slice(Object[] objects, int begin, int length) {
|
||||||
Object[] result = new Object[length];
|
Object[] result = new Object[length];
|
||||||
for ( int i=0; i<length; i++ ) {
|
System.arraycopy( objects, begin, result, 0, length );
|
||||||
result[i] = objects[begin+i];
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,25 +156,27 @@ public final class ArrayHelper {
|
||||||
|
|
||||||
public static String[] join(String[] x, String[] y) {
|
public static String[] join(String[] x, String[] y) {
|
||||||
String[] result = new String[ x.length + y.length ];
|
String[] result = new String[ x.length + y.length ];
|
||||||
for ( int i=0; i<x.length; i++ ) result[i] = x[i];
|
System.arraycopy( x, 0, result, 0, x.length );
|
||||||
for ( int i=0; i<y.length; i++ ) result[i+x.length] = y[i];
|
System.arraycopy( y, 0, result, x.length, y.length );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] join(String[] x, String[] y, boolean[] use) {
|
public static String[] join(String[] x, String[] y, boolean[] use) {
|
||||||
String[] result = new String[ x.length + countTrue(use) ];
|
String[] result = new String[ x.length + countTrue(use) ];
|
||||||
for ( int i=0; i<x.length; i++ ) result[i] = x[i];
|
System.arraycopy( x, 0, result, 0, x.length );
|
||||||
int k = x.length;
|
int k = x.length;
|
||||||
for ( int i=0; i<y.length; i++ ) {
|
for ( int i=0; i<y.length; i++ ) {
|
||||||
if ( use[i] ) result[k++] = y[i];
|
if ( use[i] ) {
|
||||||
|
result[k++] = y[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int[] join(int[] x, int[] y) {
|
public static int[] join(int[] x, int[] y) {
|
||||||
int[] result = new int[ x.length + y.length ];
|
int[] result = new int[ x.length + y.length ];
|
||||||
for ( int i=0; i<x.length; i++ ) result[i] = x[i];
|
System.arraycopy( x, 0, result, 0, x.length );
|
||||||
for ( int i=0; i<y.length; i++ ) result[i+x.length] = y[i];
|
System.arraycopy( y, 0, result, x.length, y.length );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,9 +234,7 @@ public final class ArrayHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addAll(Collection collection, Object[] array) {
|
public static void addAll(Collection collection, Object[] array) {
|
||||||
for ( int i=0; i<array.length; i++ ) {
|
collection.addAll( Arrays.asList( array ) );
|
||||||
collection.add( array[i] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String[] EMPTY_STRING_ARRAY = {};
|
public static final String[] EMPTY_STRING_ARRAY = {};
|
||||||
|
|
|
@ -27,6 +27,7 @@ package org.hibernate.util;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class StringHelper {
|
public final class StringHelper {
|
||||||
|
|
||||||
|
@ -85,6 +86,12 @@ public final class StringHelper {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String repeat(char character, int times) {
|
||||||
|
char[] buffer = new char[times];
|
||||||
|
Arrays.fill( buffer, character );
|
||||||
|
return new String( buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String replace(String template, String placeholder, String replacement) {
|
public static String replace(String template, String placeholder, String replacement) {
|
||||||
return replace( template, placeholder, replacement, false );
|
return replace( template, placeholder, replacement, false );
|
||||||
|
|
|
@ -104,6 +104,49 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
||||||
return new FunctionalTestClassTestSuite( ASTParserLoadingTest.class );
|
return new FunctionalTestClassTestSuite( ASTParserLoadingTest.class );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testJPAQLQualifiedIdentificationVariables() {
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
Human me = new Human();
|
||||||
|
me.setName( new Name( "Steve", null, "Ebersole" ) );
|
||||||
|
Human joe = new Human();
|
||||||
|
me.setName( new Name( "Joe", null, "Ebersole" ) );
|
||||||
|
me.setFamily( new HashMap() );
|
||||||
|
me.getFamily().put( "son", joe );
|
||||||
|
s.save( me );
|
||||||
|
s.save( joe );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
List results = s.createQuery( "select entry(h.family) from Human h" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
Object result = results.get(0);
|
||||||
|
assertTrue( Map.Entry.class.isAssignableFrom( result.getClass() ) );
|
||||||
|
Map.Entry entry = (Map.Entry) result;
|
||||||
|
assertTrue( String.class.isAssignableFrom( entry.getKey().getClass() ) );
|
||||||
|
assertTrue( Human.class.isAssignableFrom( entry.getValue().getClass() ) );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
results = s.createQuery( "select distinct key(h.family) from Human h" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
Object key = results.get(0);
|
||||||
|
assertTrue( String.class.isAssignableFrom( key.getClass() ) );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.delete( me );
|
||||||
|
s.delete( joe );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
public void testPaginationWithPolymorphicQuery() {
|
public void testPaginationWithPolymorphicQuery() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
|
|
|
@ -8,3 +8,7 @@ log4j.rootLogger=info, stdout
|
||||||
|
|
||||||
log4j.logger.org.hibernate.test=info
|
log4j.logger.org.hibernate.test=info
|
||||||
log4j.logger.org.hibernate.tool.hbm2ddl=debug
|
log4j.logger.org.hibernate.tool.hbm2ddl=debug
|
||||||
|
log4j.logger.org.hibernate.hql.ast.QueryTranslatorImpl=trace
|
||||||
|
log4j.logger.org.hibernate.hql.ast.HqlSqlWalker=trace
|
||||||
|
log4j.logger.org.hibernate.hql.ast.SqlGenerator=trace
|
||||||
|
log4j.logger.org.hibernate.hql.ast.AST=trace
|
Loading…
Reference in New Issue