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

org.apache.flink.table.sources.TableSourceValidation 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.sources;

import org.apache.flink.annotation.Internal;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.table.api.TableSchema;
import org.apache.flink.table.api.ValidationException;
import org.apache.flink.table.expressions.ResolvedFieldReference;
import org.apache.flink.table.sources.tsextractors.TimestampExtractor;
import org.apache.flink.table.sources.tsextractors.TimestampExtractorUtils;
import org.apache.flink.table.utils.TableSchemaUtils;
import org.apache.flink.table.utils.TypeMappingUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

/** Logic to validate {@link TableSource} types. */
@Internal
public class TableSourceValidation {

    /**
     * Validates a TableSource.
     *
     * 
    *
  • checks that all fields of the schema can be resolved *
  • checks that resolved fields have the correct type *
  • checks that the time attributes are correctly configured. *
* * @param tableSource The {@link TableSource} for which the time attributes are checked. */ public static void validateTableSource(TableSource tableSource, TableSchema schema) { List rowtimeAttributes = getRowtimeAttributes(tableSource); Optional proctimeAttribute = getProctimeAttribute(tableSource); validateNoGeneratedColumns(schema); validateSingleRowtimeAttribute(rowtimeAttributes); validateRowtimeAttributesExistInSchema(rowtimeAttributes, schema); validateProctimeAttributesExistInSchema(proctimeAttribute, schema); validateLogicalToPhysicalMapping(tableSource, schema); validateTimestampExtractorArguments(rowtimeAttributes, tableSource); validateNotOverlapping(rowtimeAttributes, proctimeAttribute); } /** * Checks if the given {@link TableSource} defines a rowtime attribute. * * @param tableSource The table source to check. * @return true if the given table source defines rowtime attribute */ public static boolean hasRowtimeAttribute(TableSource tableSource) { return !getRowtimeAttributes(tableSource).isEmpty(); } /** * Checks if the given {@link TableSource} defines a proctime attribute. * * @param tableSource The table source to check. * @return true if the given table source defines proctime attribute. */ public static boolean hasProctimeAttribute(TableSource tableSource) { return getProctimeAttribute(tableSource).isPresent(); } private static void validateSingleRowtimeAttribute( List rowtimeAttributes) { if (rowtimeAttributes.size() > 1) { throw new ValidationException( "Currently, only a single rowtime attribute is supported. " + "Please remove all but one RowtimeAttributeDescriptor."); } } private static void validateRowtimeAttributesExistInSchema( List rowtimeAttributes, TableSchema tableSchema) { rowtimeAttributes.forEach( r -> { if (!tableSchema.getFieldDataType(r.getAttributeName()).isPresent()) { throw new ValidationException( String.format( "Found a rowtime attribute for field '%s' but it does not exist in the Table. TableSchema: %s", r.getAttributeName(), tableSchema)); } }); } private static void validateProctimeAttributesExistInSchema( Optional proctimeAttribute, TableSchema tableSchema) { proctimeAttribute.ifPresent( r -> { if (!tableSchema.getFieldDataType(r).isPresent()) { throw new ValidationException( String.format( "Found a proctime attribute for field '%s' but it does not exist in the Table. TableSchema: %s", r, tableSchema)); } }); } private static void validateNotOverlapping( List rowtimeAttributes, Optional proctimeAttribute) { proctimeAttribute.ifPresent( proctime -> { if (rowtimeAttributes.stream() .anyMatch( rowtimeAttribute -> rowtimeAttribute.getAttributeName().equals(proctime))) { throw new ValidationException( String.format( "Field '%s' must not be processing time and rowtime attribute at the same time.", proctime)); } }); } private static void validateLogicalToPhysicalMapping( TableSource tableSource, TableSchema schema) { final Function fieldMapping = getNameMappingFunction(tableSource); // if we can TypeMappingUtils.computePhysicalIndicesOrTimeAttributeMarkers( tableSource, schema.getTableColumns(), true, // this makes no difference for validation, we don't care about the returned // indices fieldMapping); } private static Function getNameMappingFunction(TableSource tableSource) { final Function fieldMapping; if (tableSource instanceof DefinedFieldMapping && ((DefinedFieldMapping) tableSource).getFieldMapping() != null) { Map fieldsMap = ((DefinedFieldMapping) tableSource).getFieldMapping(); if (fieldsMap != null) { fieldMapping = fieldsMap::get; } else { fieldMapping = Function.identity(); } } else { fieldMapping = Function.identity(); } return fieldMapping; } private static void validateTimestampExtractorArguments( List descriptors, TableSource tableSource) { if (descriptors.size() == 1) { TimestampExtractor extractor = descriptors.get(0).getTimestampExtractor(); TypeInformation[] types = Arrays.stream( TimestampExtractorUtils.getAccessedFields( extractor, tableSource.getProducedDataType(), getNameMappingFunction(tableSource))) .map(ResolvedFieldReference::resultType) .toArray(TypeInformation[]::new); extractor.validateArgumentFields(types); } } private static void validateNoGeneratedColumns(TableSchema tableSchema) { if (!TableSchemaUtils.containsPhysicalColumnsOnly(tableSchema)) { throw new ValidationException( "TableSource#getTableSchema should only contain physical columns, schema: \n" + tableSchema); } } /** Returns a list with all rowtime attribute descriptors of the {@link TableSource}. */ private static List getRowtimeAttributes( TableSource tableSource) { if (tableSource instanceof DefinedRowtimeAttributes) { return ((DefinedRowtimeAttributes) tableSource).getRowtimeAttributeDescriptors(); } return Collections.emptyList(); } /** Returns the proctime attribute of the {@link TableSource} if it is defined. */ private static Optional getProctimeAttribute(TableSource tableSource) { if (tableSource instanceof DefinedProctimeAttribute) { return Optional.ofNullable( ((DefinedProctimeAttribute) tableSource).getProctimeAttribute()); } return Optional.empty(); } private TableSourceValidation() {} }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy