protected void doMatch(
      RelOptRuleCall call, ScanPrel scan, ProjectPrel project, FilterPrel filter) {
    final RexNode condition = filter.getCondition();

    InfoSchemaGroupScan groupScan = (InfoSchemaGroupScan) scan.getGroupScan();
    if (groupScan.isFilterPushedDown()) {
      return;
    }

    LogicalExpression conditionExp =
        DrillOptiq.toDrill(
            new DrillParseContext(PrelUtil.getPlannerSettings(call.getPlanner())),
            project != null ? project : scan,
            condition);
    InfoSchemaFilterBuilder filterBuilder = new InfoSchemaFilterBuilder(conditionExp);
    InfoSchemaFilter infoSchemaFilter = filterBuilder.build();
    if (infoSchemaFilter == null) {
      return; // no filter pushdown ==> No transformation.
    }

    final InfoSchemaGroupScan newGroupsScan =
        new InfoSchemaGroupScan(groupScan.getTable(), infoSchemaFilter);
    newGroupsScan.setFilterPushedDown(true);

    RelNode input = ScanPrel.create(scan, filter.getTraitSet(), newGroupsScan, scan.getRowType());
    if (project != null) {
      input =
          project.copy(project.getTraitSet(), input, project.getProjects(), filter.getRowType());
    }

    if (filterBuilder.isAllExpressionsConverted()) {
      // Filter can be removed as all expressions in the filter are converted and pushed to scan
      call.transformTo(input);
    } else {
      call.transformTo(filter.copy(filter.getTraitSet(), ImmutableList.of(input)));
    }
  }
 @Override
 public boolean matches(RelOptRuleCall call) {
   final ScanPrel scan = (ScanPrel) call.rel(1);
   GroupScan groupScan = scan.getGroupScan();
   return groupScan instanceof InfoSchemaGroupScan;
 }