📄 hqlsqlwalker.java
字号:
fromElement.setWithClauseFragment( visitor.getJoinAlias(), "(" + sql.getSQL() + ")" ); } catch( SemanticException e ) { throw e; } catch( InvalidWithClauseException 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 InvalidWithClauseException( "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 ); versionValueNode.setNextSibling( currentFirstSelectExprNode );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -