diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/ASTNode.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/ASTNode.java index c8dbe97..cb767f9 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/ASTNode.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/ASTNode.java @@ -20,6 +20,7 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.List; import org.antlr.runtime.Token; import org.antlr.runtime.tree.CommonTree; @@ -31,8 +32,12 @@ */ public class ASTNode extends CommonTree implements Node,Serializable { private static final long serialVersionUID = 1L; - + private transient StringBuffer astStr; private transient ASTNodeOrigin origin; + private transient int startIndx = -1; + private transient int endIndx = -1; + private transient ASTNode rootNode; + private transient boolean modifiedTree; public ASTNode() { } @@ -81,6 +86,7 @@ public Tree dupNode() { * * @see org.apache.hadoop.hive.ql.lib.Node#getName() */ + @Override public String getName() { return (Integer.valueOf(super.getToken().getType())).toString(); } @@ -126,4 +132,134 @@ private StringBuilder dump(StringBuilder sb, String ws) { } return sb; } + + private ASTNode getRootNode (boolean useMemoizedRoot) { + if (useMemoizedRoot && rootNode != null && rootNode.parent == null && + !rootNode.modifiedTree) { + return rootNode; + } + ASTNode retNode = this; + while (retNode.parent != null) { + retNode = (ASTNode) retNode.parent; + } + rootNode.modifiedTree = false; + return rootNode=retNode; + } + + private boolean hasValidMemoizedString() { + return astStr != null; + } + + private void resetRootInformation() { + // Reset the previously stored string + if (rootNode != null) { + rootNode.astStr = null; + rootNode.modifiedTree = true; + } + // The root might have changed because of tree modifications. + // Compute the new root for this tree and set the astStr. + getRootNode(false).astStr = null; + } + + private int getMemoizedStringLen() { + return astStr == null ? 0 : astStr.length(); + } + + private String getMemoizedSubString(int start, int end) { + return (astStr == null || start < 0 || end > astStr.length() || start >= end) ? null : + astStr.subSequence(start, end).toString(); + } + + private void addtoMemoizedString(String string) { + if (astStr == null) { + astStr = new StringBuffer(); + } + astStr.append(string); + } + + @Override + public void setParent(Tree t) { + super.setParent(t); + resetRootInformation(); + } + + @Override + public void addChild(Tree t) { + super.addChild(t); + resetRootInformation(); + } + + @Override + public void addChildren(List kids) { + super.addChildren(kids); + resetRootInformation(); + } + + @Override + public void setChild(int i, Tree t) { + super.setChild(i, t); + resetRootInformation(); + } + + @Override + public void insertChild(int i, Object t) { + super.insertChild(i, t); + resetRootInformation(); + } + + @Override + public Object deleteChild(int i) { + Object ret = super.deleteChild(i); + resetRootInformation(); + return ret; + } + + @Override + public void replaceChildren(int startChildIndex, int stopChildIndex, Object t) { + super.replaceChildren(startChildIndex, stopChildIndex, t); + resetRootInformation(); + } + + @Override + public String toStringTree() { + boolean rootNotModified = rootNode != null && !rootNode.modifiedTree; + // The tree modifier functions invalidate the astStr, rootNode, etc. + // Hence, we can use the memoized root node and string values here. + ASTNode rootNode = (ASTNode)this.getRootNode(true); + + // If rootNotModified is false, then startIndx and endIndx will be stale. + if (rootNotModified && rootNode.hasValidMemoizedString() && startIndx >= 0 && + endIndx <= rootNode.getMemoizedStringLen()) { + return rootNode.getMemoizedSubString(startIndx, endIndx); + } + return toStringTree(rootNode); + } + + private String toStringTree(ASTNode rootNode) { + this.rootNode = rootNode; + startIndx = rootNode.getMemoizedStringLen(); + // Leaf node + if ( children==null || children.size()==0 ) { + rootNode.addtoMemoizedString(this.toString()); + endIndx = rootNode.getMemoizedStringLen(); + return this.toString(); + } + if ( !isNil() ) { + rootNode.addtoMemoizedString("("); + rootNode.addtoMemoizedString(this.toString()); + rootNode.addtoMemoizedString(" "); + } + for (int i = 0; children!=null && i < children.size(); i++) { + ASTNode t = (ASTNode)children.get(i); + if ( i>0 ) { + rootNode.addtoMemoizedString(" "); + } + t.toStringTree(rootNode); + } + if ( !isNil() ) { + rootNode.addtoMemoizedString(")"); + } + endIndx = rootNode.getMemoizedStringLen(); + return rootNode.getMemoizedSubString(startIndx, endIndx); + } }