Added map_agg aggregation function
Use checkCondition for approx_distinct
Use HTTPS for documentation links to Maven Central
Add download link for benchmark-driver
Use direct references to top-level documents
Remove duplicate function documentation
Improve documentation for map_agg
Fix formatting
Add optimizer that turns RIGHT into LEFT join
Remove SinkNode

It exists for historical reasons. Output from plan nodes was purely logical,
so SinkNodes were used to enforce the shape of the output across distribution
boundaries (similar to OutputNode).

This change moves the layout tracking to the plan fragment and the enforcement
to the physical execution planner.
Rename ExchangeNode to RemoteSourceNode
Rename PlanDistribution.NONE to SINGLE for clarity
Improve rendering of distributed plan explanation

It's now rendered as a sequence of fragments with additional information.
For example:

Fragment 2 [SINGLE]
    Output layout: [orderstatus, sum]
    - Output[orderstatus, _col1]
            _col1 := sum
        - RemoteSource[1] => [orderstatus:varchar, $hashvalue:bigint, sum:double]

Fragment 1 [FIXED]
    Output layout: [orderstatus, $hashvalue, sum]
    - Aggregate(FINAL)[orderstatus] => [orderstatus:varchar, $hashvalue:bigint, sum:double]
            sum := "sum"("sum_9")
        - RemoteSource[0] => [orderstatus:varchar, $hashvalue:bigint, sum_9:double]

Fragment 0 [SOURCE]
    Output layout: [orderstatus, $hashvalue, sum_9]
    Output partitioning: [orderstatus]
    - Aggregate(PARTIAL)[orderstatus] => [orderstatus:varchar, $hashvalue:bigint, sum_9:double]
            sum_9 := "sum"("totalprice")
        - Project => [orderstatus:varchar, totalprice:double, $hashvalue:bigint]
                $hashvalue := "combine_hash"(0, "$operator$hash_code"("orderstatus"))
            - Filter[("orderstatus" = 'O')] => [orderstatus:varchar, totalprice:double]
                - TableScan[default:default:tpch:orders:2, original constraint=('O' = "orderstatus")] => [orderstatus:varchar, totalprice:double]
                        orderstatus := default:default:orderstatus:3:varchar
                        totalprice := default:default:totalprice:4:double
Improve rendering of Output node in EXPLAIN
Add convenience method to ChildReplacer
Implement distributed planning as an optimizer

Add a new optimizer (AddExchanges) that introduces Exchange node
at the right places in the logical plan and determines partitioning
and placement requirements.

This also adds basic partition awareness, which can result in better plans:

E.g.,

 SELECT custkey, sum(t)
 FROM (
   SELECT custkey, count(*) t
   FROM orders
   GROUP BY custkey
 )
 GROUP BY custkey

Before:

 Fragment 3 [SINGLE]
     Output layout: [custkey, sum]
     - Output[custkey, _col1] => [custkey:bigint, sum:bigint]
             _col1 := sum
         - RemoteSource[2] => [custkey:bigint, sum:bigint]

 Fragment 2 [FIXED]
     Output layout: [custkey, sum]
     - Aggregate(FINAL)[custkey] => [custkey:bigint, sum:bigint]
             sum := "sum"("sum_18")
         - RemoteSource[1] => [custkey:bigint, sum_18:bigint]

 Fragment 1 [FIXED]
     Output layout: [custkey, sum_18]
     Output partitioning: [custkey]
     - Aggregate(PARTIAL)[custkey] => [custkey:bigint, sum_18:bigint]
             sum_18 := "sum"("count")
         - Aggregate(FINAL)[custkey] => [custkey:bigint, count:bigint]
                 count := "count"("count_17")
             - RemoteSource[0] => [custkey:bigint, count_17:bigint]

 Fragment 0 [SOURCE]
     Output layout: [custkey, count_17]
     Output partitioning: [custkey]
     - Aggregate(PARTIAL)[custkey] => [custkey:bigint, count_17:bigint]
             count_17 := "count"(*)
         - TableScan[tpch:tpch:orders:sf1.0, original constraint=true] => [custkey:bigint]
                 custkey := tpch:tpch:custkey:1

After:

 Fragment 2 [SINGLE]
     Output layout: [custkey, sum]
     - Output[custkey, _col1] => [custkey:bigint, sum:bigint]
             _col1 := sum
         - RemoteSource[1] => [custkey:bigint, sum:bigint]

 Fragment 1 [FIXED]
     Output layout: [custkey, sum]
     - Aggregate[custkey] => [custkey:bigint, sum:bigint]
             sum := "sum"("count")
         - Aggregate(FINAL)[custkey] => [custkey:bigint, count:bigint]
                 count := "count"("count_17")
             - RemoteSource[0] => [custkey:bigint, count_17:bigint]

 Fragment 0 [SOURCE]
     Output layout: [custkey, count_17]
     Output partitioning: [custkey]
     - Aggregate(PARTIAL)[custkey] => [custkey:bigint, count_17:bigint]
             count_17 := "count"(*)
         - TableScan[tpch:tpch:orders:sf1.0, original constraint=true] => [custkey:bigint]
                 custkey := tpch:tpch:custkey:1
Add missing support for UnionNode to DistributedExecutionPlanner
Fix SymbolExtractor implementation for UnionNode
Add missing json serialization for UnionNode
Generate local union when inputs are unpartitioned

Before:

 Fragment 2 [SINGLE]
     Output layout: [expr_3]
     - Output[_col0] => [expr_3:bigint]
             _col0 := expr_3
         - RemoteSource[0,1] => [expr_3:bigint]

 Fragment 0 [SINGLE]
     Output layout: [expr]
     - Project => [expr:bigint]
             expr := 1
         - Values => []
                 ()

 Fragment 1 [SOURCE]
     Output layout: [orderkey]
     - TableScan[tpch:tpch:orders:sf1.0, original constraint=true] => [orderkey:bigint]
             orderkey := tpch:tpch:orderkey:0

After:

 Fragment 1 [SINGLE]
     Output layout: [expr_3]
     - Output[_col0] => [expr_3:bigint]
             _col0 := expr_3
         - Union => [expr_3:bigint]
             - Project => [expr:bigint]
                     expr := 1
                 - Values => []
                         ()
             - RemoteSource[0] => [expr_3:bigint]

 Fragment 0 [SOURCE]
     Output layout: [orderkey]
     - TableScan[tpch:tpch:orders:sf1.0, original constraint=true] => [orderkey:bigint]
             orderkey := tpch:tpch:orderkey:0