All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.table.planner.plan.abilities.source.FilterPushDownSpec Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.flink.table.planner.plan.abilities.source;

import org.apache.flink.table.api.TableException;
import org.apache.flink.table.connector.source.DynamicTableSource;
import org.apache.flink.table.connector.source.abilities.SupportsFilterPushDown;
import org.apache.flink.table.expressions.Expression;
import org.apache.flink.table.expressions.ResolvedExpression;
import org.apache.flink.table.expressions.resolver.ExpressionResolver;
import org.apache.flink.table.planner.calcite.FlinkTypeFactory;
import org.apache.flink.table.planner.plan.utils.RexNodeToExpressionConverter;

import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.annotation.JsonCreator;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.annotation.JsonTypeName;

import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.TimeZone;
import java.util.stream.Collectors;

import static org.apache.flink.util.Preconditions.checkNotNull;

/**
 * A sub-class of {@link SourceAbilitySpec} that can not only serialize/deserialize the filter
 * to/from JSON, but also can push the filter into a {@link SupportsFilterPushDown}.
 */
@JsonTypeName("FilterPushDown")
public class FilterPushDownSpec extends SourceAbilitySpecBase {
    public static final String FIELD_NAME_PREDICATES = "predicates";

    @JsonProperty(FIELD_NAME_PREDICATES)
    private final List predicates;

    @JsonCreator
    public FilterPushDownSpec(@JsonProperty(FIELD_NAME_PREDICATES) List predicates) {
        this.predicates = new ArrayList<>(checkNotNull(predicates));
    }

    @Override
    public void apply(DynamicTableSource tableSource, SourceAbilityContext context) {
        SupportsFilterPushDown.Result result = apply(predicates, tableSource, context);
        if (result.getAcceptedFilters().size() != predicates.size()) {
            throw new TableException("All predicates should be accepted here.");
        }
    }

    public static SupportsFilterPushDown.Result apply(
            List predicates,
            DynamicTableSource tableSource,
            SourceAbilityContext context) {
        if (tableSource instanceof SupportsFilterPushDown) {
            RexNodeToExpressionConverter converter =
                    new RexNodeToExpressionConverter(
                            new RexBuilder(FlinkTypeFactory.INSTANCE()),
                            context.getSourceRowType().getFieldNames().toArray(new String[0]),
                            context.getFunctionCatalog(),
                            context.getCatalogManager(),
                            TimeZone.getTimeZone(context.getTableConfig().getLocalTimeZone()));
            List filters =
                    predicates.stream()
                            .map(
                                    p -> {
                                        scala.Option expr = p.accept(converter);
                                        if (expr.isDefined()) {
                                            return expr.get();
                                        } else {
                                            throw new TableException(
                                                    String.format(
                                                            "%s can not be converted to Expression, please make sure %s can accept %s.",
                                                            p.toString(),
                                                            tableSource.getClass().getSimpleName(),
                                                            p.toString()));
                                        }
                                    })
                            .collect(Collectors.toList());
            ExpressionResolver resolver =
                    ExpressionResolver.resolverFor(
                                    context.getTableConfig(),
                                    name -> Optional.empty(),
                                    context.getFunctionCatalog()
                                            .asLookup(
                                                    str -> {
                                                        throw new TableException(
                                                                "We should not need to lookup any expressions at this point");
                                                    }),
                                    context.getCatalogManager().getDataTypeFactory(),
                                    (sqlExpression, inputSchema) -> {
                                        throw new TableException(
                                                "SQL expression parsing is not supported at this location.");
                                    })
                            .build();
            return ((SupportsFilterPushDown) tableSource).applyFilters(resolver.resolve(filters));
        } else {
            throw new TableException(
                    String.format(
                            "%s does not support SupportsFilterPushDown.",
                            tableSource.getClass().getName()));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy