docs: private AbstractPlanNode handleWindowedOperators(AbstractPlanNode root) {
          // Get the windowed expression.  We need to set its output
          // schema from the display list.
          WindowFunctionExpression winExpr = m_parsedSelect.getWindowFunctionExpressions().get(0);
          assert(winExpr != null);
  
          // This will set the output schema to contain the
          // windowed schema column only.  In generateOutputSchema
          // we will add the input columns.
          WindowFunctionPlanNode pnode = new WindowFunctionPlanNode();
          pnode.setWindowFunctionExpression(winExpr);
          // We always need an order by plan node, even if the sort
          // is optimized away by an index.  This may be turned
          // into an inline order by in a MergeReceivePlanNode.
          IndexUseForOrderBy scanNode = findScanNodeForWindowFunction(root);
          AbstractPlanNode cnode = null;
          int winfunc = (scanNode == null) ? SubPlanAssembler.NO_INDEX_USE : scanNode.getWindowFunctionUsesIndex();
          // If we have an index which is compatible with the statement
          // level order by, and we have a window function which can't
          // use the index we have to ignore the statement level order by
          // index use.  We will need to order the input according to the
          // window function first, and that will in general invalidate the
          // statement level order by ordering.
          if ((SubPlanAssembler.STATEMENT_LEVEL_ORDER_BY_INDEX == winfunc)
                  || (SubPlanAssembler.NO_INDEX_USE == winfunc)) {
              // No index.  Calculate the expression order here and stuff it into
              // the order by node.  Note that if we support more than one window
              // function this would be the case when scanNode.getWindowFunctionUsesIndex()
              // returns a window function number which is different from the number
              // of winExpr.
              List<AbstractExpression> partitionByExpressions = winExpr.getPartitionByExpressions();
              // If the order by expression list contains a partition by expression then
              // we won't have to sort by it twice.  We sort by the partition by expressions
              // first, and we don't care what order we sort by them.  So, find the
              // sort direction in the order by list and use that in the partition by
              // list, and then mark that it was deleted in the order by
              // list.
              //
              // We choose to make this dontsort rather than dosort because the
              // Java default value for boolean is false, and we want to sort by
              // default.
              boolean dontsort[] = new boolean[winExpr.getOrderbySize()];
              List<AbstractExpression> orderByExpressions = winExpr.getOrderByExpressions();
              List<SortDirectionType>  orderByDirections  = winExpr.getOrderByDirections();
              OrderByPlanNode onode = new OrderByPlanNode();
              for (int idx = 0; idx < winExpr.getPartitionbySize(); ++idx) {
                  SortDirectionType pdir = SortDirectionType.ASC;
                  AbstractExpression partitionByExpression = partitionByExpressions.get(idx);
                  int sidx = winExpr.getSortIndexOfOrderByExpression(partitionByExpression);
                  if (0 <= sidx) {
                      pdir = orderByDirections.get(sidx);
                      dontsort[sidx] = true;
                  }
                  onode.addSortExpression(partitionByExpression, pdir);
              }
              for (int idx = 0; idx < winExpr.getOrderbySize(); ++idx) {
                  if (!dontsort[idx]) {
                      AbstractExpression orderByExpr = orderByExpressions.get(idx);
                      SortDirectionType  orderByDir  = orderByDirections.get(idx);
                      onode.addSortExpression(orderByExpr, orderByDir);
                  }
              }
              onode.addAndLinkChild(root);
              cnode = onode;
          } else {
              assert(scanNode != null);
              // This means the index is good for this window function.
              // If this is an MP statement we still need to generate the
              // order by node, because we may need to turn it into an
              // inline order by node of a MergeReceive node.
              assert( 0 == scanNode.getWindowFunctionUsesIndex() );
              if (m_partitioning.requiresTwoFragments()) {
                  OrderByPlanNode onode = new OrderByPlanNode();
                  SortDirectionType dir = scanNode.getSortOrderFromIndexScan();
                  assert(dir != SortDirectionType.INVALID);
                  // This was created when the index was determined.
                  // We cached it in the scan node.
                  List<AbstractExpression> orderExprs = scanNode.getFinalExpressionOrderFromIndexScan();
                  assert(orderExprs != null);
                  for (AbstractExpression ae : orderExprs) {
                      onode.addSortExpression(ae, dir);
                  }
                  // Link in the OrderByNode.
                  onode.addAndLinkChild(root);
                  cnode = onode;
              } else {
                  // Don't create and link in the order by node.
                  cnode = root;
              }
          }
          pnode.addAndLinkChild(cnode);
          return pnode;
      }