📄 joinnode.java
字号:
public void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { generateCore(acb, mb, INNERJOIN, null, null); } /** * Generate the code for a qualified join node. * * @exception StandardException Thrown on error */ public void generateCore(ActivationClassBuilder acb, MethodBuilder mb, int joinType) throws StandardException { generateCore(acb, mb, joinType, joinClause, subqueryList); } /** * Do the generation work for the join node hierarchy. * * @param acb The ActivationClassBuilder * @param mb the method the code is to go into * @param joinType The join type * @param joinClause The join clause, if any * @param subquerys The list of subqueries in the join clause, if any * * @return Expression The generated Expression * * @exception StandardException Thrown on error */ protected void generateCore(ActivationClassBuilder acb, MethodBuilder mb, int joinType, ValueNode joinClause, SubqueryList subquerys) throws StandardException { /* Put the predicates back into the tree */ if (joinPredicates != null) { joinClause = joinPredicates.restorePredicates(); joinPredicates = null; } /* Get the next ResultSet #, so that we can number this ResultSetNode, its * ResultColumnList and ResultSet. */ assignResultSetNumber(); /* Set the point of attachment in all subqueries attached * to this node. */ if (subquerys != null && subquerys.size() > 0) { subquerys.setPointOfAttachment(resultSetNumber); } // build up the tree. /* Generate the JoinResultSet */ /* Nested loop and hash are the only join strategy currently supporteds. * Right outer joins are transformed into left outer joins. */ String joinResultSetString; if (joinType == LEFTOUTERJOIN) { joinResultSetString = ((Optimizable) rightResultSet).getTrulyTheBestAccessPath(). getJoinStrategy().halfOuterJoinResultSetMethodName(); } else { joinResultSetString = ((Optimizable) rightResultSet).getTrulyTheBestAccessPath(). getJoinStrategy().joinResultSetMethodName(); } acb.pushGetResultSetFactoryExpression(mb); int nargs = getJoinArguments(acb, mb, joinClause); mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, joinResultSetString, ClassName.NoPutResultSet, nargs); } /** * Get the arguments to the join result set. * * @param acb The ActivationClassBuilder for the class we're building. * @param mb the method the generated code is going into * @param joinClause The join clause, if any * * @return The array of arguments to the join result set * * @exception StandardException Thrown on error */ private int getJoinArguments(ActivationClassBuilder acb, MethodBuilder mb, ValueNode joinClause) throws StandardException { int numArgs = getNumJoinArguments(); leftResultSet.generate(acb, mb); // arg 1 mb.push(leftResultSet.resultColumns.size()); // arg 2 rightResultSet.generate(acb, mb); // arg 3 mb.push(rightResultSet.resultColumns.size()); // arg 4 acb.pushThisAsActivation(mb); // arg 5 // Get our final cost estimate based on child estimates. costEstimate = getFinalCostEstimate(); // for the join clause, we generate an exprFun // that evaluates the expression of the clause // against the current row of the child's result. // if the join clause is empty, we generate a function // that just returns true. (Performance tradeoff: have // this function for the empty join clause, or have // all non-empty join clauses check for a null at runtime). // generate the function and initializer: // Note: Boolean lets us return nulls (boolean would not) // private Boolean exprN() // { // return <<joinClause.generate(ps)>>; // } // static Method exprN = method pointer to exprN; // if there is no join clause, we just pass a null Expression. if (joinClause == null) { mb.pushNull(ClassName.GeneratedMethod); // arg 6 } else { // this sets up the method and the static field. // generates: // Object userExprFun { } MethodBuilder userExprFun = acb.newUserExprFun(); // join clause knows it is returning its value; /* generates: * return <joinClause.generate(acb)>; * and adds it to userExprFun */ joinClause.generate(acb, userExprFun); userExprFun.methodReturn(); // we are done modifying userExprFun, complete it. userExprFun.complete(); // join clause is used in the final result set as an access of the new static // field holding a reference to this new method. // generates: // ActivationClass.userExprFun // which is the static field that "points" to the userExprFun // that evaluates the where clause. acb.pushMethodReference(mb, userExprFun); // arg 6 } mb.push(resultSetNumber); // arg 7 addOuterJoinArguments(acb, mb); // Does right side return a single row oneRowRightSide(acb, mb); // estimated row count mb.push(costEstimate.rowCount()); // estimated cost mb.push(costEstimate.getEstimatedCost()); closeMethodArgument(acb, mb); return numArgs; } /** * @see ResultSetNode#getFinalCostEstimate * * Get the final CostEstimate for this JoinNode. * * @return The final CostEstimate for this JoinNode, which is sum * the costs for the inner and outer table. The number of rows, * though, is that for the inner table only. */ public CostEstimate getFinalCostEstimate() throws StandardException { // If we already found it, just return it. if (finalCostEstimate != null) return finalCostEstimate; CostEstimate leftCE = leftResultSet.getFinalCostEstimate(); CostEstimate rightCE = rightResultSet.getFinalCostEstimate(); finalCostEstimate = getNewCostEstimate(); finalCostEstimate.setCost( leftCE.getEstimatedCost() + rightCE.getEstimatedCost(), rightCE.rowCount(), rightCE.rowCount()); return finalCostEstimate; } protected void oneRowRightSide(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { mb.push(rightResultSet.isOneRowResultSet()); mb.push(rightResultSet.isNotExists()); //join is for NOT EXISTS } /** * Return the number of arguments to the join result set. This will * be overridden for other types of joins (for example, outer joins). */ protected int getNumJoinArguments() { return 12; } /** * Generate and add any arguments specifict to outer joins. * (Expected to be overriden, where appropriate, in subclasses.) * * @param acb The ActivationClassBuilder * @param mb the method the generated code is to go into * * return The number of args added * * @exception StandardException Thrown on error */ protected int addOuterJoinArguments(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { return 0; } /** * Convert the joinType to a string. * * @param int The joinType as an int. * * @return String The joinType as a String. */ public static String joinTypeToString(int joinType) { switch(joinType) { case INNERJOIN: return "INNER JOIN"; case CROSSJOIN: return "CROSS JOIN"; case LEFTOUTERJOIN: return "LEFT OUTER JOIN"; case RIGHTOUTERJOIN: return "RIGHT OUTER JOIN"; case FULLOUTERJOIN: return "FULL OUTER JOIN"; case UNIONJOIN: return "UNION JOIN"; default: if (SanityManager.DEBUG) { SanityManager.ASSERT(false, "Unexpected joinType"); } return null; } } protected PredicateList getLeftPredicateList() throws StandardException { if (leftPredicateList == null) leftPredicateList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); return leftPredicateList; } protected PredicateList getRightPredicateList() throws StandardException { if (rightPredicateList == null) rightPredicateList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); return rightPredicateList; } /** * Get the lock mode for the target of an update statement * (a delete or update). The update mode will always be row for * CurrentOfNodes. It will be table if there is no where clause. * * @return The lock mode */ public int updateTargetLockMode() { /* Always use row locking if we have a join node. * We can only have a join node if there is a subquery that * got flattened, hence there is a restriction. */ return TransactionController.MODE_RECORD; } /** * Mark this node and its children as not being a flattenable join. * * @return Nothing. */ void notFlattenableJoin() { flattenableJoin = false; leftResultSet.notFlattenableJoin(); rightResultSet.notFlattenableJoin(); } /** * Is this FromTable a JoinNode which can be flattened into * the parents FromList. * * @return boolean Whether or not this FromTable can be flattened. */ public boolean isFlattenableJoinNode() { return flattenableJoin; } /** * Return whether or not the underlying ResultSet tree * is ordered on the specified columns. * RESOLVE - This method currently only considers the outermost table * of the query block. * * @param crs The specified ColumnReference[] * @param permuteOrdering Whether or not the order of the CRs in the array can be permuted * @param fbtVector Vector that is to be filled with the FromBaseTable * * @return Whether the underlying ResultSet tree * is ordered on the specified column. * * @exception StandardException Thrown on error */ boolean isOrderedOn(ColumnReference[] crs, boolean permuteOrdering, Vector fbtVector) throws StandardException { /* RESOLVE - easiest thing for now is to only consider the leftmost child */ return leftResultSet.isOrderedOn(crs, permuteOrdering, fbtVector); } /** * 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 * * @return Nothing */ public void printSubNodes(int depth) { if (SanityManager.DEBUG) { super.printSubNodes(depth); if (subqueryList != null) { printLabel(depth, "subqueryList: "); subqueryList.treePrint(depth + 1); } if (joinClause != null) { printLabel(depth, "joinClause: "); joinClause.treePrint(depth + 1); } if (joinPredicates.size() != 0) { printLabel(depth, "joinPredicates: "); joinPredicates.treePrint(depth + 1); } if (usingClause != null) { printLabel(depth, "usingClause: "); usingClause.treePrint(depth + 1); } } } void setSubqueryList(SubqueryList subqueryList) { this.subqueryList = subqueryList; } void setAggregateVector(Vector aggregateVector) { this.aggregateVector = aggregateVector; } /** * 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). */ 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). */ ResultSetNode getLogicalRightResultSet() { return rightResultSet; } /** * Accept a visitor, and call v.visit() * on child nodes as necessary. * * @param v the visitor * * @exception StandardException on error */ public Visitable accept(Visitor v) throws StandardException { if (v.skipChildren(this)) { return v.visit(this); } Visitable returnNode = super.accept(v); if (resultColumns != null && !v.stopTraversal()) { resultColumns = (ResultColumnList)resultColumns.accept(v); } if (joinClause != null && !v.stopTraversal()) { joinClause = (ValueNode)joinClause.accept(v); } if (usingClause != null && !v.stopTraversal()) { usingClause = (ResultColumnList)usingClause.accept(v); } return returnNode; } // This method returns the table references in Join node, and this may be // needed for LOJ reordering. For example, we may have the following query: // (T JOIN S) LOJ (X LOJ Y) // The top most LOJ may be a join betw T and X and thus we can reorder the // LOJs. However, as of 10/2002, we don't reorder LOJ mixed with join. public JBitSet LOJgetReferencedTables(int numTables) throws StandardException { JBitSet map = new JBitSet(numTables); map = (JBitSet) leftResultSet.LOJgetReferencedTables(numTables); if (map == null) return null; else map.or((JBitSet) rightResultSet.LOJgetReferencedTables(numTables)); return map; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -