/* * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software;Designed and Developed mainly by many Chinese * opensource volunteers. you can redistribute it and/or modify it under the * terms of the GNU General Public License version 2 only, as published by the * Free Software Foundation. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Any questions about this component can be directed to it's project Web address * https://code.google.com/p/opencloudb/. * */ package com.akiban.sql.parser; import com.akiban.sql.StandardException; import java.util.Properties; /** * A JoinNode represents a join result set for either of the basic DML * operations: SELECT and INSERT. For INSERT - SELECT, any of the * fields in a JoinNode can be used (the JoinNode represents * the (join) SELECT statement in the INSERT - SELECT). For INSERT, * the resultColumns in the selectList will contain the names of the columns * being inserted into or updated. * */ public class JoinNode extends TableOperatorNode { /* Join semantics */ public static enum JoinType { INNER, CROSS, LEFT_OUTER, RIGHT_OUTER, FULL_OUTER, UNION, STRAIGHT } /** If this flag is true, this node represents a natural join. */ private boolean naturalJoin; private ValueNode joinClause; private ResultColumnList usingClause; //User provided optimizer overrides private Properties joinOrderStrategyProperties; /** * Initializer for a JoinNode. * * @param leftResult The ResultSetNode on the left side of this join * @param rightResult The ResultSetNode on the right side of this join * @param onClause The ON clause * @param usingClause The USING clause * @param selectList The result column list for the join * @param tableProperties Properties list associated with the table * @param joinOrderStrategyProperties User provided optimizer overrides * * @exception StandardException Thrown on error */ public void init(Object leftResult, Object rightResult, Object onClause, Object usingClause, Object selectList, Object tableProperties, Object joinOrderStrategyProperties) throws StandardException { super.init(leftResult, rightResult, tableProperties); resultColumns = (ResultColumnList)selectList; joinClause = (ValueNode)onClause; this.usingClause = (ResultColumnList)usingClause; this.joinOrderStrategyProperties = (Properties)joinOrderStrategyProperties; } /** * Fill this node with a deep copy of the given node. */ public void copyFrom(QueryTreeNode node) throws StandardException { super.copyFrom(node); JoinNode other = (JoinNode)node; this.naturalJoin = other.naturalJoin; this.joinClause = (ValueNode)getNodeFactory().copyNode(other.joinClause, getParserContext()); this.usingClause = (ResultColumnList)getNodeFactory().copyNode(other.usingClause, getParserContext()); this.joinOrderStrategyProperties = other.joinOrderStrategyProperties; // TODO: Clone? } /** * Convert the joinType to a string. * * @param joinType The joinType as an enum. * * @return String The joinType as a String. */ public static String joinTypeToString(JoinType joinType) { switch(joinType) { case INNER: return "INNER JOIN"; case CROSS: return "CROSS JOIN"; case LEFT_OUTER: return "LEFT OUTER JOIN"; case RIGHT_OUTER: return "RIGHT OUTER JOIN"; case FULL_OUTER: return "FULL OUTER JOIN"; case UNION: return "UNION JOIN"; default: assert false : "Unexpected joinType"; return null; } } public ValueNode getJoinClause() { return joinClause; } public void setJoinClause(ValueNode joinClause) { this.joinClause = joinClause; } public ResultColumnList getUsingClause() { return usingClause; } public void setUsingClause(ResultColumnList usingClause) { this.usingClause = usingClause; } /** * Convert this object to a String. See comments in QueryTreeNode.java * for how this should be done for tree printing. * * @return This object as a String */ public String toString() { String str = super.toString(); if (naturalJoin) str = "naturalJoin: " + naturalJoin + "\n" + str; if (joinOrderStrategyProperties != null) str = "joinOrderStrategyProperties: " + joinOrderStrategyProperties + "\n" + str; return str; } /** * Prints the sub-nodes of this object. See QueryTreeNode.java for * how tree printing is supposed to work. * * @param depth The depth of this node in the tree */ public void printSubNodes(int depth) { super.printSubNodes(depth); if (joinClause != null) { printLabel(depth, "joinClause: "); joinClause.treePrint(depth + 1); } if (usingClause != null) { printLabel(depth, "usingClause: "); usingClause.treePrint(depth + 1); } } /** * Flag this as a natural join so that an implicit USING clause will * be generated in the bind phase. */ void setNaturalJoin() { naturalJoin = true; } /** Is this a natural join? */ public boolean isNaturalJoin() { return naturalJoin; } /** * Return the logical left result set for this qualified * join node. * (For RIGHT OUTER JOIN, the left is the right * and the right is the left and the JOIN is the NIOJ). */ public ResultSetNode getLogicalLeftResultSet() { return leftResultSet; } /** * Return the logical right result set for this qualified * join node. * (For RIGHT OUTER JOIN, the left is the right * and the right is the left and the JOIN is the NIOJ). */ public ResultSetNode getLogicalRightResultSet() { return rightResultSet; } /** * Accept the visitor for all visitable children of this node. * * @param v the visitor * * @exception StandardException on error */ void acceptChildren(Visitor v) throws StandardException { super.acceptChildren(v); if (resultColumns != null) { resultColumns = (ResultColumnList)resultColumns.accept(v); } if (joinClause != null) { joinClause = (ValueNode)joinClause.accept(v); } if (usingClause != null) { usingClause = (ResultColumnList)usingClause.accept(v); } } }