Source:
<code>public ExplainPlan getExplainPlan() throws SQLException { List<String> planSteps = Lists.newArrayList(delegate.getExplainPlan().getPlanSteps()); if (where != null) { planSteps.add("CLIENT FILTER BY " + where.toString()); } if (groupBy.isEmpty()) { planSteps.add("CLIENT AGGREGATE INTO SINGLE ROW"); } else if (groupBy.isOrderPreserving()) { planSteps.add("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); <START> } else if (useHashAgg) { <END> planSteps.add("CLIENT HASH AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); } else { planSteps.add("CLIENT SORTED BY " + groupBy.getKeyExpressions().toString()); planSteps.add("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); } if (having != null) { planSteps.add("CLIENT AFTER-AGGREGATION FILTER BY " + having.toString()); } if (statement.isDistinct() && statement.isAggregate()) { planSteps.add("CLIENT DISTINCT ON " + projector.toString()); } if (offset != null) { planSteps.add("CLIENT OFFSET " + offset); } if (orderBy.getOrderByExpressions().isEmpty()) { if (limit != null) { planSteps.add("CLIENT " + limit + " ROW LIMIT"); } } else { planSteps.add("CLIENT" + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + " SORTED BY " + orderBy.getOrderByExpressions().toString()); } if (context.getSequenceManager().getSequenceCount() > 0) { int nSequences = context.getSequenceManager().getSequenceCount(); planSteps.add("CLIENT RESERVE VALUES FROM " + nSequences + " SEQUENCE" + (nSequences == 1 ? "" : "S")); } return new ExplainPlan(planSteps); }</code><technical_language>Add CLIENT SORTED line if sorting required for hash aggregate</technical_language>

Target:
public ExplainPlan getExplainPlan() throws SQLException { List<String> planSteps = Lists.newArrayList(delegate.getExplainPlan().getPlanSteps()); if (where != null) { planSteps.add("CLIENT FILTER BY " + where.toString()); } if (groupBy.isEmpty()) { planSteps.add("CLIENT AGGREGATE INTO SINGLE ROW"); } else if (groupBy.isOrderPreserving()) { planSteps.add("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); } else if (useHashAgg) { planSteps.add("CLIENT HASH AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); if (orderBy == OrderBy.FWD_ROW_KEY_ORDER_BY || orderBy == OrderBy.REV_ROW_KEY_ORDER_BY) { planSteps.add("CLIENT SORTED BY " + groupBy.getKeyExpressions().toString()); } } else { planSteps.add("CLIENT SORTED BY " + groupBy.getKeyExpressions().toString()); planSteps.add("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); } if (having != null) { planSteps.add("CLIENT AFTER-AGGREGATION FILTER BY " + having.toString()); } if (statement.isDistinct() && statement.isAggregate()) { planSteps.add("CLIENT DISTINCT ON " + projector.toString()); } if (offset != null) { planSteps.add("CLIENT OFFSET " + offset); } if (orderBy.getOrderByExpressions().isEmpty()) { if (limit != null) { planSteps.add("CLIENT " + limit + " ROW LIMIT"); } } else { planSteps.add("CLIENT" + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + " SORTED BY " + orderBy.getOrderByExpressions().toString()); } if (context.getSequenceManager().getSequenceCount() > 0) { int nSequences = context.getSequenceManager().getSequenceCount(); planSteps.add("CLIENT RESERVE VALUES FROM " + nSequences + " SEQUENCE" + (nSequences == 1 ? "" : "S")); } return new ExplainPlan(planSteps); }