class AddJoinConditionColumnsToSources implements OptimizerRule {

    @Override
    public PlanNode execute( QueryContext context,
                             PlanNode plan,
                             LinkedList<OptimizerRule> ruleStack ) {
        final boolean includeSourceName = context.getHints().qualifyExpandedColumnNames;

        // For each of the JOIN nodes ...
        for (PlanNode joinNode : plan.findAllAtOrBelow(Type.JOIN)) {
            JoinCondition condition = joinNode.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
            if (condition instanceof EquiJoinCondition) {
                EquiJoinCondition equiJoinCondition = (EquiJoinCondition)condition;
                SelectorName selector1 = equiJoinCondition.selector1Name();
                Column joinColumn1 = columnFor(equiJoinCondition.selector1Name(),
                                               equiJoinCondition.getProperty1Name(),
                                               includeSourceName);
                Column joinColumn2 = columnFor(equiJoinCondition.selector2Name(),
                                               equiJoinCondition.getProperty2Name(),
                                               includeSourceName);

                // Figure out which side of the join condition goes with which side of the plan nodes ...
                PlanNode left = joinNode.getFirstChild();
                PlanNode right = joinNode.getLastChild();
                if (left.getSelectors().contains(selector1)) {
                    addEquiJoinColumn(context, left, joinColumn1);
                    addEquiJoinColumn(context, right, joinColumn2);
                } else {
                    addEquiJoinColumn(context, left, joinColumn2);
                    addEquiJoinColumn(context, right, joinColumn1);
                }
            }

        }
        return plan;
    }

}