/** * Check whether a join is valid. Invalid joins are CROSS JOIN, FULL OUTER JOIN, any join without * criteria, any join with no equality criteria, and any outer join that has the outer side not * the same as the dependent. * * @param joinNode The join node to check * @param sourceNode The access node being considered * @param analysisRecord TODO * @return True if valid for making dependent * @throws TeiidComponentException * @throws QueryMetadataException */ boolean isValidJoin(PlanNode joinNode, PlanNode sourceNode, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException { JoinType jtype = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE); // Check that join is not a CROSS join or FULL OUTER join if (jtype.equals(JoinType.JOIN_CROSS) || jtype.equals(JoinType.JOIN_FULL_OUTER)) { sourceNode.recordDebugAnnotation( "parent join is CROSS or FULL OUTER", null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return false; } if (!joinNode.getExportedCorrelatedReferences().isEmpty()) { sourceNode.recordDebugAnnotation( "parent join has a correlated nested table", null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return false; } // Check that join criteria exist List jcrit = (List) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA); if (jcrit == null || jcrit.size() == 0) { sourceNode.recordDebugAnnotation( "parent join has has no join criteria", null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return false; } if (joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS) == null) { sourceNode.recordDebugAnnotation( "parent join has no equa-join predicates", null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return false; } // Check that for a left or right outer join the dependent side must be the inner if (jtype.isOuter() && JoinUtil.getInnerSideJoinNodes(joinNode)[0] != sourceNode) { sourceNode.recordDebugAnnotation( "node is on outer side of the join", null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return false; } return true; }
PlanNode chooseDepWithoutCosting( PlanNode rootNode1, PlanNode rootNode2, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException { PlanNode sourceNode1 = FrameUtil.findJoinSourceNode(rootNode1); PlanNode sourceNode2 = null; if (rootNode2 != null) { sourceNode2 = FrameUtil.findJoinSourceNode(rootNode2); } if (sourceNode1.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS)) { if (sourceNode2 != null && sourceNode2.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS)) { // Return null - query planning should fail because both access nodes // have unsatisfied access patterns rootNode1 .getParent() .recordDebugAnnotation( "both children have unsatisfied access patterns", null, "Neither node can be made dependent", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return null; } rootNode1.recordDebugAnnotation( "unsatisfied access pattern detected", null, "marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return rootNode1; } else if (sourceNode2 != null && sourceNode2.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS)) { // Access node 2 has unsatisfied access pattern, // so try to make node 2 dependent sourceNode2.recordDebugAnnotation( "unsatisfied access pattern detected", null, "marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return rootNode2; } // Check for hints, which over-rule heuristics if (sourceNode1.hasProperty(NodeConstants.Info.MAKE_DEP)) { sourceNode1.recordDebugAnnotation( "MAKE_DEP hint detected", null, "marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ rootNode1.setProperty(Info.MAKE_DEP, sourceNode1.getProperty(Info.MAKE_DEP)); return rootNode1; } else if (sourceNode2 != null && sourceNode2.hasProperty(NodeConstants.Info.MAKE_DEP)) { sourceNode2.recordDebugAnnotation( "MAKE_DEP hint detected", null, "marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ rootNode2.setProperty(Info.MAKE_DEP, sourceNode2.getProperty(Info.MAKE_DEP)); return rootNode2; } else if (sourceNode1.hasBooleanProperty(NodeConstants.Info.MAKE_IND) && sourceNode2 != null) { sourceNode2.recordDebugAnnotation( "MAKE_IND hint detected", null, "marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return rootNode2; } else if (sourceNode2 != null && sourceNode2.hasBooleanProperty(NodeConstants.Info.MAKE_IND)) { sourceNode1.recordDebugAnnotation( "MAKE_IND hint detected", null, "marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$ return rootNode1; } return null; }