presto-main/src/main/java/io/prestosql/sql/planner/sanity/ValidateAggregationsWithDefaultValues.java/Visitor/visitAggregation
class Visitor:        @Override
        public Optional<SeenExchanges> visitAggregation(AggregationNode node, Void context)
        {
            Optional<SeenExchanges> seenExchangesOptional = aggregatedSeenExchanges(node.getSources());

            if (node.getStep().equals(PARTIAL)) {
                return Optional.of(new SeenExchanges(false, false));
            }

            if (node.getStep().equals(INTERMEDIATE)) {
                return seenExchangesOptional;
            }

            // We only validate FINAL aggregations with empty grouping set
            if (!node.getStep().equals(FINAL) || !node.hasEmptyGroupingSet()) {
                return Optional.empty();
            }

            checkState(seenExchangesOptional.isPresent(), "No partial aggregation below final aggregation");
            SeenExchanges seenExchanges = seenExchangesOptional.get();

            if (seenExchanges.remoteRepartitionExchange) {
                // Final aggregation separated from partial by remote repartition exchange.
                return Optional.empty();
            }

            // No remote repartition exchange between final and partial aggregation.
            // Make sure that final aggregation operators are executed on a single node.
            ActualProperties globalProperties = PropertyDerivations.derivePropertiesRecursively(node, metadata, session, types, typeAnalyzer);
            checkArgument(forceSingleNode || globalProperties.isSingleNode(),
                    "Final aggregation with default value not separated from partial aggregation by remote hash exchange");

            if (!seenExchanges.localRepartitionExchange) {
                // No local repartition exchange between final and partial aggregation.
                // Make sure that final aggregation operators are executed by single thread.
                StreamProperties localProperties = StreamPropertyDerivations.derivePropertiesRecursively(node, metadata, session, types, typeAnalyzer);
                checkArgument(localProperties.isSingleStream(),
                        "Final aggregation with default value not separated from partial aggregation by local hash exchange");
            }

            return Optional.empty();
        }