📄 hqlsqlwalker.java
字号:
NodeTraverser traverser = new NodeTraverser( visitor );
traverser.traverseDepthFirst( hqlSqlWithNode );
FromElement referencedFromElement = visitor.getReferencedFromElement();
if ( referencedFromElement != fromElement ) {
throw new SemanticException( "with-clause expressions did not reference from-clause element to which the with-clause was associated" );
}
SqlGenerator sql = new SqlGenerator( getSessionFactoryHelper().getFactory() );
sql.whereExpr( hqlSqlWithNode.getFirstChild() );
fromElement.setWithClauseFragment( visitor.getJoinAlias(), "(" + sql.getSQL() + ")" );
}
catch( SemanticException e ) {
throw e;
}
catch ( Exception e) {
throw new SemanticException( e.getMessage() );
}
}
private static class WithClauseVisitor implements NodeTraverser.VisitationStrategy {
private FromElement referencedFromElement;
private String joinAlias;
public void visit(AST node) {
// todo : currently expects that the individual with expressions apply to the same sql table join.
// This may not be the case for joined-subclass where the property values
// might be coming from different tables in the joined hierarchy. At some
// point we should expand this to support that capability. However, that has
// some difficulties:
// 1) the biggest is how to handle ORs when the individual comparisons are
// linked to different sql joins.
// 2) here we would need to track each comparison individually, along with
// the join alias to which it applies and then pass that information
// back to the FromElement so it can pass it along to the JoinSequence
if ( node instanceof DotNode ) {
DotNode dotNode = ( DotNode ) node;
FromElement fromElement = dotNode.getFromElement();
if ( referencedFromElement != null ) {
if ( fromElement != referencedFromElement ) {
throw new HibernateException( "with-clause referenced two different from-clause elements" );
}
}
else {
referencedFromElement = fromElement;
joinAlias = extractAppliedAlias( dotNode );
// todo : temporary
// needed because currently persister is the one that
// creates and renders the join fragments for inheritence
// hierarchies...
if ( !joinAlias.equals( referencedFromElement.getTableAlias() ) ) {
throw new HibernateException( "with clause can only reference columns in the driving table" );
}
}
}
}
private String extractAppliedAlias(DotNode dotNode) {
return dotNode.getText().substring( 0, dotNode.getText().indexOf( '.' ) );
}
public FromElement getReferencedFromElement() {
return referencedFromElement;
}
public String getJoinAlias() {
return joinAlias;
}
}
/**
* Sets the current 'FROM' context.
*
* @param fromNode The new 'FROM' context.
* @param inputFromNode The from node from the input AST.
*/
protected void pushFromClause(AST fromNode, AST inputFromNode) {
FromClause newFromClause = ( FromClause ) fromNode;
newFromClause.setParentFromClause( currentFromClause );
currentFromClause = newFromClause;
}
/**
* Returns to the previous 'FROM' context.
*/
private void popFromClause() {
currentFromClause = currentFromClause.getParentFromClause();
}
protected void lookupAlias(AST aliasRef)
throws SemanticException {
FromElement alias = currentFromClause.getFromElement( aliasRef.getText() );
FromReferenceNode aliasRefNode = ( FromReferenceNode ) aliasRef;
aliasRefNode.setFromElement( alias );
}
protected void setImpliedJoinType(int joinType) {
impliedJoinType = JoinProcessor.toHibernateJoinType( joinType );
}
public int getImpliedJoinType() {
return impliedJoinType;
}
protected AST lookupProperty(AST dot, boolean root, boolean inSelect) throws SemanticException {
DotNode dotNode = ( DotNode ) dot;
FromReferenceNode lhs = dotNode.getLhs();
AST rhs = lhs.getNextSibling();
switch ( rhs.getType() ) {
case SqlTokenTypes.ELEMENTS:
case SqlTokenTypes.INDICES:
if ( log.isDebugEnabled() ) {
log.debug( "lookupProperty() " + dotNode.getPath() + " => " + rhs.getText() + "(" + lhs.getPath() + ")" );
}
CollectionFunction f = ( CollectionFunction ) rhs;
// Re-arrange the tree so that the collection function is the root and the lhs is the path.
f.setFirstChild( lhs );
lhs.setNextSibling( null );
dotNode.setFirstChild( f );
resolve( lhs ); // Don't forget to resolve the argument!
f.resolve( inSelect ); // Resolve the collection function now.
return f;
default:
// Resolve everything up to this dot, but don't resolve the placeholders yet.
dotNode.resolveFirstChild();
return dotNode;
}
}
protected boolean isNonQualifiedPropertyRef(AST ident) {
final String identText = ident.getText();
if ( currentFromClause.isFromElementAlias( identText ) ) {
return false;
}
List fromElements = currentFromClause.getExplicitFromElements();
if ( fromElements.size() == 1 ) {
final FromElement fromElement = ( FromElement ) fromElements.get( 0 );
try {
log.trace( "attempting to resolve property [" + identText + "] as a non-qualified ref" );
return fromElement.getPropertyMapping( identText ).toType( identText ) != null;
}
catch( QueryException e ) {
// Should mean that no such property was found
}
}
return false;
}
protected AST lookupNonQualifiedProperty(AST property) throws SemanticException {
final FromElement fromElement = ( FromElement ) currentFromClause.getExplicitFromElements().get( 0 );
AST syntheticDotNode = generateSyntheticDotNodeForNonQualifiedPropertyRef( property, fromElement );
return lookupProperty( syntheticDotNode, false, getCurrentClauseType() == HqlSqlTokenTypes.SELECT );
}
private AST generateSyntheticDotNodeForNonQualifiedPropertyRef(AST property, FromElement fromElement) {
AST dot = getASTFactory().create( DOT, "{non-qualified-property-ref}" );
// TODO : better way?!?
( ( DotNode ) dot ).setPropertyPath( ( ( FromReferenceNode ) property ).getPath() );
IdentNode syntheticAlias = ( IdentNode ) getASTFactory().create( IDENT, "{synthetic-alias}" );
syntheticAlias.setFromElement( fromElement );
syntheticAlias.setResolved();
dot.setFirstChild( syntheticAlias );
dot.addChild( property );
return dot;
}
protected void processQuery(AST select, AST query) throws SemanticException {
if ( log.isDebugEnabled() ) {
log.debug( "processQuery() : " + query.toStringTree() );
}
try {
QueryNode qn = ( QueryNode ) query;
// Was there an explicit select expression?
boolean explicitSelect = select != null && select.getNumberOfChildren() > 0;
if ( !explicitSelect ) {
// No explicit select expression; render the id and properties
// projection lists for every persister in the from clause into
// a single 'token node'.
//TODO: the only reason we need this stuff now is collection filters,
// we should get rid of derived select clause completely!
createSelectClauseFromFromClause( qn );
}
else {
// Use the explicitly declared select expression; determine the
// return types indicated by each select token
useSelectClause( select );
}
// After that, process the JOINs.
// Invoke a delegate to do the work, as this is farily complex.
JoinProcessor joinProcessor = new JoinProcessor( astFactory, queryTranslatorImpl );
joinProcessor.processJoins( qn, isSubQuery() );
// Attach any mapping-defined "ORDER BY" fragments
Iterator itr = qn.getFromClause().getProjectionList().iterator();
while ( itr.hasNext() ) {
final FromElement fromElement = ( FromElement ) itr.next();
// if ( fromElement.isFetch() && fromElement.isCollectionJoin() ) {
if ( fromElement.isFetch() && fromElement.getQueryableCollection() != null ) {
// Does the collection referenced by this FromElement
// specify an order-by attribute? If so, attach it to
// the query's order-by
if ( fromElement.getQueryableCollection().hasOrdering() ) {
String orderByFragment = fromElement
.getQueryableCollection()
.getSQLOrderByString( fromElement.getCollectionTableAlias() );
qn.getOrderByClause().addOrderFragment( orderByFragment );
}
if ( fromElement.getQueryableCollection().hasManyToManyOrdering() ) {
String orderByFragment = fromElement.getQueryableCollection()
.getManyToManyOrderByString( fromElement.getTableAlias() );
qn.getOrderByClause().addOrderFragment( orderByFragment );
}
}
}
}
finally {
popFromClause();
}
}
protected void postProcessDML(RestrictableStatement statement) throws SemanticException {
statement.getFromClause().resolve();
FromElement fromElement = ( FromElement ) statement.getFromClause().getFromElements().get( 0 );
Queryable persister = fromElement.getQueryable();
// Make #@%$^#^&# sure no alias is applied to the table name
fromElement.setText( persister.getTableName() );
// append any filter fragments; the EMPTY_MAP is used under the assumption that
// currently enabled filters should not affect this process
if ( persister.getDiscriminatorType() != null ) {
new SyntheticAndFactory( getASTFactory() ).addDiscriminatorWhereFragment(
statement,
persister,
java.util.Collections.EMPTY_MAP,
fromElement.getTableAlias()
);
}
}
protected void postProcessUpdate(AST update) throws SemanticException {
UpdateStatement updateStatement = ( UpdateStatement ) update;
postProcessDML( updateStatement );
}
protected void postProcessDelete(AST delete) throws SemanticException {
postProcessDML( ( DeleteStatement ) delete );
}
public static boolean supportsIdGenWithBulkInsertion(IdentifierGenerator generator) {
return SequenceGenerator.class.isAssignableFrom( generator.getClass() )
|| PostInsertIdentifierGenerator.class.isAssignableFrom( generator.getClass() );
}
protected void postProcessInsert(AST insert) throws SemanticException, QueryException {
InsertStatement insertStatement = ( InsertStatement ) insert;
insertStatement.validate();
SelectClause selectClause = insertStatement.getSelectClause();
Queryable persister = insertStatement.getIntoClause().getQueryable();
if ( !insertStatement.getIntoClause().isExplicitIdInsertion() ) {
// We need to generate ids as part of this bulk insert.
//
// Note that this is only supported for sequence-style generators and
// post-insert-style generators; basically, only in-db generators
IdentifierGenerator generator = persister.getIdentifierGenerator();
if ( !supportsIdGenWithBulkInsertion( generator ) ) {
throw new QueryException( "can only generate ids as part of bulk insert with either sequence or post-insert style generators" );
}
AST idSelectExprNode = null;
if ( SequenceGenerator.class.isAssignableFrom( generator.getClass() ) ) {
String seqName = ( String ) ( ( SequenceGenerator ) generator ).generatorKey();
String nextval = sessionFactoryHelper.getFactory().getDialect().getSelectSequenceNextValString( seqName );
idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, nextval );
}
else {
//Don't need this, because we should never ever be selecting no columns in an insert ... select...
//and because it causes a bug on DB2
/*String idInsertString = sessionFactoryHelper.getFactory().getDialect().getIdentityInsertString();
if ( idInsertString != null ) {
idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, idInsertString );
}*/
}
if ( idSelectExprNode != null ) {
AST currentFirstSelectExprNode = selectClause.getFirstChild();
selectClause.setFirstChild( idSelectExprNode );
idSelectExprNode.setNextSibling( currentFirstSelectExprNode );
insertStatement.getIntoClause().prependIdColumnSpec();
}
}
final boolean includeVersionProperty = persister.isVersioned() &&
!insertStatement.getIntoClause().isExplicitVersionInsertion() &&
persister.isVersionPropertyInsertable();
if ( includeVersionProperty ) {
// We need to seed the version value as part of this bulk insert
VersionType versionType = persister.getVersionType();
AST versionValueNode = null;
if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) {
versionValueNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
( ( ParameterNode ) versionValueNode ).setHqlParameterSpecification( paramSpec );
parameters.add( 0, paramSpec );
}
else {
if ( isIntegral( versionType ) ) {
try {
Object seedValue = versionType.seed( null );
versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, seedValue.toString() );
}
catch( Throwable t ) {
throw new QueryException( "could not determine seed value for version on bulk insert [" + versionType + "]" );
}
}
else if ( isDatabaseGeneratedTimestamp( versionType ) ) {
String functionName = sessionFactoryHelper.getFactory().getDialect().getCurrentTimestampSQLFunctionName();
versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, functionName );
}
else {
throw new QueryException( "cannot handle version type [" + versionType + "] on bulk inserts with dialects not supporting parameters in insert-select statements" );
}
}
AST currentFirstSelectExprNode = selectClause.getFirstChild();
selectClause.setFirstChild( versionValueNode );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -