/**
  * Derives the list of column names suitable for NATURAL JOIN. These are the columns that occur
  * exactly once on each side of the join.
  *
  * @param leftRowType Row type of left input to the join
  * @param rightRowType Row type of right input to the join
  * @return List of columns that occur once on each side
  */
 public static List<String> deriveNaturalJoinColumnList(
     RelDataType leftRowType, RelDataType rightRowType) {
   List<String> naturalColumnNames = new ArrayList<String>();
   final List<String> leftNames = leftRowType.getFieldNames();
   final List<String> rightNames = rightRowType.getFieldNames();
   for (String name : leftNames) {
     if ((Collections.frequency(leftNames, name) == 1)
         && (Collections.frequency(rightNames, name) == 1)) {
       naturalColumnNames.add(name);
     }
   }
   return naturalColumnNames;
 }
 private List<AggregateCall> transformAggCalls(
     RelDataTypeFactory typeFactory, int nGroupCols, List<AggregateCall> origCalls) {
   List<AggregateCall> newCalls = new ArrayList<AggregateCall>();
   int iInput = nGroupCols;
   for (AggregateCall origCall : origCalls) {
     if (origCall.isDistinct()
         || !SUPPORTED_AGGREGATES.containsKey(origCall.getAggregation().getClass())) {
       return null;
     }
     Aggregation aggFun;
     RelDataType aggType;
     if (origCall.getAggregation().getName().equals("COUNT")) {
       aggFun = new SqlSumEmptyIsZeroAggFunction(origCall.getType());
       SqlAggFunction af = (SqlAggFunction) aggFun;
       final AggregateRelBase.AggCallBinding binding =
           new AggregateRelBase.AggCallBinding(
               typeFactory, af, Collections.singletonList(origCall.getType()), nGroupCols);
       // count(any) is always not null, however nullability of sum might
       // depend on the number of columns in GROUP BY.
       // Here we use SUM0 since we are sure we will not face nullable
       // inputs nor we'll face empty set.
       aggType = af.inferReturnType(binding);
     } else {
       aggFun = origCall.getAggregation();
       aggType = origCall.getType();
     }
     AggregateCall newCall =
         new AggregateCall(
             aggFun,
             origCall.isDistinct(),
             Collections.singletonList(iInput),
             aggType,
             origCall.getName());
     newCalls.add(newCall);
     ++iInput;
   }
   return newCalls;
 }
  public static void getSchemaObjectMonikers(
      SqlValidatorCatalogReader catalogReader, List<String> names, List<SqlMoniker> hints) {
    // Assume that the last name is 'dummy' or similar.
    List<String> subNames = Util.skipLast(names);
    hints.addAll(catalogReader.getAllSchemaObjectNames(subNames));

    // If the name has length 0, try prepending the name of the default
    // schema. So, the empty name would yield a list of tables in the
    // default schema, as well as a list of schemas from the above code.
    if (subNames.size() == 0) {
      hints.addAll(
          catalogReader.getAllSchemaObjectNames(
              Collections.singletonList(catalogReader.getSchemaName())));
    }
  }
        public void onMatch(RelOptRuleCall call) {
          ProjectRel project = (ProjectRel) call.rels[0];
          List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(project.getChildExps()));
          if (reduceExpressions(project, expList)) {
            call.transformTo(
                new ProjectRel(
                    project.getCluster(),
                    project.getChild(),
                    expList.toArray(new RexNode[expList.size()]),
                    project.getRowType(),
                    ProjectRel.Flags.Boxed,
                    Collections.<RelCollation>emptyList()));

            // New plan is absolutely better than old plan.
            call.getPlanner().setImportance(project, 0.0);
          }
        }