📄 identnode.java
字号:
// $Id: IdentNode.java 10059 2006-06-28 02:37:56Z steve.ebersole@jboss.com $package org.hibernate.hql.ast.tree;import antlr.SemanticException;import antlr.collections.AST;import org.hibernate.QueryException;import org.hibernate.dialect.function.SQLFunction;import org.hibernate.hql.antlr.SqlTokenTypes;import org.hibernate.hql.ast.util.ColumnHelper;import org.hibernate.persister.collection.QueryableCollection;import org.hibernate.persister.entity.Queryable;import org.hibernate.sql.JoinFragment;import org.hibernate.type.CollectionType;import org.hibernate.type.Type;import org.hibernate.util.StringHelper;import java.util.List;/** * Represents an identifier all by itself, which may be a function name, * a class alias, or a form of naked property-ref depending on the * context. * * @author josh Aug 16, 2004 7:20:55 AM */public class IdentNode extends FromReferenceNode implements SelectExpression { private static final int UNKNOWN = 0; private static final int PROPERTY_REF = 1; private static final int COMPONENT_REF = 2; private boolean nakedPropertyRef = false; public void resolveIndex(AST parent) throws SemanticException { // An ident node can represent an index expression if the ident // represents a naked property ref // *Note: this makes the assumption (which is currently the case // in the hql-sql grammar) that the ident is first resolved // itself (addrExpr -> resolve()). The other option, if that // changes, is to call resolve from here; but it is // currently un-needed overhead. if (!(isResolved() && nakedPropertyRef)) { throw new UnsupportedOperationException(); } String propertyName = getOriginalText(); if (!getDataType().isCollectionType()) { throw new SemanticException("Collection expected; [" + propertyName + "] does not refer to a collection property"); } // TODO : most of below was taken verbatim from DotNode; should either delegate this logic or super-type it CollectionType type = (CollectionType) getDataType(); String role = type.getRole(); QueryableCollection queryableCollection = getSessionFactoryHelper().requireQueryableCollection(role); String alias = null; // DotNode uses null here... String columnTableAlias = getFromElement().getTableAlias(); int joinType = JoinFragment.INNER_JOIN; boolean fetch = false; FromElementFactory factory = new FromElementFactory( getWalker().getCurrentFromClause(), getFromElement(), propertyName, alias, getFromElement().toColumns(columnTableAlias, propertyName, false), true ); FromElement elem = factory.createCollection(queryableCollection, role, joinType, fetch, true); setFromElement(elem); getWalker().addQuerySpaces(queryableCollection.getCollectionSpaces()); // Always add the collection's query spaces. } public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) { if (!isResolved()) { if (getWalker().getCurrentFromClause().isFromElementAlias(getText())) { if (resolveAsAlias()) { setResolved(); // We represent a from-clause alias } } else if (parent != null && parent.getType() == SqlTokenTypes.DOT) { DotNode dot = (DotNode) parent; if (parent.getFirstChild() == this) { if (resolveAsNakedComponentPropertyRefLHS(dot)) { // we are the LHS of the DOT representing a naked comp-prop-ref setResolved(); } } else { if (resolveAsNakedComponentPropertyRefRHS(dot)) { // we are the RHS of the DOT representing a naked comp-prop-ref setResolved(); } } } else { int result = resolveAsNakedPropertyRef(); if (result == PROPERTY_REF) { // we represent a naked (simple) prop-ref setResolved(); } else if (result == COMPONENT_REF) { // EARLY EXIT!!! return so the resolve call explicitly coming from DotNode can // resolve this... return; } } // if we are still not resolved, we might represent a constant. // needed to add this here because the allowance of // naked-prop-refs in the grammar collides with the // definition of literals/constants ("nondeterminism"). // TODO: cleanup the grammar so that "processConstants" is always just handled from here if (!isResolved()) { try { getWalker().getLiteralProcessor().processConstant(this, false); } catch (Throwable ignore) { // just ignore it for now, it'll get resolved later... } } } } private boolean resolveAsAlias() { // This is not actually a constant, but a reference to FROM element. FromElement element = getWalker().getCurrentFromClause().getFromElement(getText()); if (element != null) { setFromElement(element); setText(element.getIdentityColumn()); setType(SqlTokenTypes.ALIAS_REF); return true; } return false; } private Type getNakedPropertyType(FromElement fromElement) { if (fromElement == null) { return null; } String property = getOriginalText(); Type propertyType = null; try { propertyType = fromElement.getPropertyType(property, property); } catch (Throwable t) { } return propertyType; } private int resolveAsNakedPropertyRef() { FromElement fromElement = locateSingleFromElement(); if (fromElement == null) { return UNKNOWN; } Queryable persister = fromElement.getQueryable(); if (persister == null) { return UNKNOWN; } Type propertyType = getNakedPropertyType(fromElement); if (propertyType == null) { // assume this ident's text does *not* refer to a property on the given persister return UNKNOWN; } if ((propertyType.isComponentType() || propertyType.isAssociationType() )) { return COMPONENT_REF; } setFromElement(fromElement); String property = getText(); String[] columns = getWalker().isSelectStatement() ? persister.toColumns(fromElement.getTableAlias(), property) : persister.toColumns(property); String text = StringHelper.join(", ", columns); setText(columns.length == 1 ? text : "(" + text + ")"); setType(SqlTokenTypes.SQL_TOKEN); // these pieces are needed for usage in select clause super.setDataType(propertyType); nakedPropertyRef = true; return PROPERTY_REF; } private boolean resolveAsNakedComponentPropertyRefLHS(DotNode parent) { FromElement fromElement = locateSingleFromElement(); if (fromElement == null) { return false; } Type componentType = getNakedPropertyType(fromElement); if ( componentType == null ) { throw new QueryException( "Unable to resolve path [" + parent.getPath() + "], unexpected token [" + getOriginalText() + "]" ); } if (!componentType.isComponentType()) { throw new QueryException("Property '" + getOriginalText() + "' is not a component. Use an alias to reference associations or collections."); } Type propertyType = null; // used to set the type of the parent dot node String propertyPath = getText() + "." + getNextSibling().getText(); try { // check to see if our "propPath" actually // represents a property on the persister propertyType = fromElement.getPropertyType(getText(), propertyPath); } catch (Throwable t) { // assume we do *not* refer to a property on the given persister return false; } setFromElement(fromElement); parent.setPropertyPath(propertyPath); parent.setDataType(propertyType); return true; } private boolean resolveAsNakedComponentPropertyRefRHS(DotNode parent) { FromElement fromElement = locateSingleFromElement(); if (fromElement == null) { return false; } Type propertyType = null; String propertyPath = parent.getLhs().getText() + "." + getText(); try { // check to see if our "propPath" actually // represents a property on the persister propertyType = fromElement.getPropertyType(getText(), propertyPath); } catch (Throwable t) { // assume we do *not* refer to a property on the given persister return false; } setFromElement(fromElement); // this piece is needed for usage in select clause super.setDataType(propertyType); nakedPropertyRef = true; return true; } private FromElement locateSingleFromElement() { List fromElements = getWalker().getCurrentFromClause().getFromElements(); if (fromElements == null || fromElements.size() != 1) { // TODO : should this be an error? return null; } FromElement element = (FromElement) fromElements.get(0); if (element.getClassAlias() != null) { // naked property-refs cannot be used with an aliased from element return null; } return element; } public Type getDataType() { Type type = super.getDataType(); if (type != null) return type; FromElement fe = getFromElement(); if (fe != null) return fe.getDataType(); SQLFunction sf = getWalker().getSessionFactoryHelper().findSQLFunction(getText()); return sf == null ? null : sf.getReturnType(null, null); } public void setScalarColumnText(int i) throws SemanticException { if (nakedPropertyRef) { // do *not* over-write the column text, as that has already been // "rendered" during resolve ColumnHelper.generateSingleScalarColumn(this, i); } else { FromElement fe = getFromElement(); if (fe != null) { setText(fe.renderScalarIdentifierSelect(i)); } else { ColumnHelper.generateSingleScalarColumn(this, i); } } } public String getDisplayText() { StringBuffer buf = new StringBuffer(); if (getType() == SqlTokenTypes.ALIAS_REF) { buf.append("{alias=").append(getOriginalText()); if (getFromElement() == null) { buf.append(", no from element"); } else { buf.append(", className=").append(getFromElement().getClassName()); buf.append(", tableAlias=").append(getFromElement().getTableAlias()); } buf.append("}"); } else { buf.append("{originalText=" + getOriginalText()).append("}"); } return buf.toString(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -