Source:
<code>public boolean feasible(Optimizable innerTable, OptimizablePredicateList predList, Optimizer optimizer, CostEstimate outerCost, boolean wasHinted, boolean skipKeyCheck) throws StandardException { int[] hashKeyColumns; ConglomerateDescriptor cd = null; OptimizerTrace tracer = optimizer.tracer(); this.missingHashKeyOK = false; if (innerTable.isTargetTable()) { return false; } if (innerTable.isBaseTable()) { cd = innerTable.getCurrentAccessPath().getConglomerateDescriptor(); } hashKeyColumns = findHashKeyColumns(innerTable, cd, predList); if (SanityManager.DEBUG) { if (hashKeyColumns == null) { if (skipKeyCheck) tracer.trace(OptimizerFlag.HJ_NO_EQUIJOIN_COLUMNS, 0, 0, 0.0, null); else tracer.trace(OptimizerFlag.HJ_SKIP_NO_JOIN_COLUMNS, 0, 0, 0.0, null); } else { tracer.trace(OptimizerFlag.HJ_HASH_KEY_COLUMNS, 0, 0, 0.0, hashKeyColumns); } } <START> if (hashKeyColumns == null && skipKeyCheck) { <END> if (innerTable instanceof FromTable && predList != null && (innerTable.isMaterializable() || innerTable.supportsMultipleInstantiations()) && optimizer instanceof OptimizerImpl && !(innerTable instanceof RowResultSetNode) && !(innerTable instanceof SetOperatorNode)) { FromTable prn = (FromTable)innerTable; while (prn instanceof ProjectRestrictNode && ((ProjectRestrictNode)prn).childResult instanceof FromTable) prn = (FromTable)((ProjectRestrictNode)prn).childResult; if (!(prn instanceof FromBaseTable)) return false; Predicate pred = null; for (int i = 0; i < predList.size(); i++) { pred = (Predicate)predList.getOptPredicate(i); if (pred.isJoinPredicate()) { missingHashKeyOK = true; return true; } } } } return hashKeyColumns!=null; }</code><technical_language>check is more more complicated in BroadcastJoinStrategy.estimateCost() check table is of type FromBaseTable</technical_language>

Target:
public boolean feasible(Optimizable innerTable, OptimizablePredicateList predList, Optimizer optimizer, CostEstimate outerCost, boolean wasHinted, boolean skipKeyCheck) throws StandardException { int[] hashKeyColumns; ConglomerateDescriptor cd = null; OptimizerTrace tracer = optimizer.tracer(); this.missingHashKeyOK = false; if (innerTable.isTargetTable()) { return false; } if (innerTable.isBaseTable()) { cd = innerTable.getCurrentAccessPath().getConglomerateDescriptor(); } hashKeyColumns = findHashKeyColumns(innerTable, cd, predList); if (SanityManager.DEBUG) { if (hashKeyColumns == null) { if (skipKeyCheck) tracer.trace(OptimizerFlag.HJ_NO_EQUIJOIN_COLUMNS, 0, 0, 0.0, null); else tracer.trace(OptimizerFlag.HJ_SKIP_NO_JOIN_COLUMNS, 0, 0, 0.0, null); } else { tracer.trace(OptimizerFlag.HJ_HASH_KEY_COLUMNS, 0, 0, 0.0, hashKeyColumns); } } if (hashKeyColumns == null && skipKeyCheck) { if (innerTable instanceof FromTable && predList != null && !outerCost.isSingleRow() && (innerTable.isMaterializable() || innerTable.supportsMultipleInstantiations()) && optimizer instanceof OptimizerImpl && !(innerTable instanceof RowResultSetNode) && !(innerTable instanceof SetOperatorNode)) { FromTable prn = (FromTable)innerTable; while (prn instanceof ProjectRestrictNode && ((ProjectRestrictNode)prn).childResult instanceof FromTable) prn = (FromTable)((ProjectRestrictNode)prn).childResult; if (!(prn instanceof FromBaseTable)) return false; Predicate pred = null; for (int i = 0; i < predList.size(); i++) { pred = (Predicate)predList.getOptPredicate(i); if (pred.isJoinPredicate()) { missingHashKeyOK = true; return true; } } } } return hashKeyColumns!=null; }