Repository: ClickHouse/ClickHouse
File: src/Storages/ObjectStorage/Utils.cpp (C++)

Code before:
    bool do_lazy_init,
    LoggerPtr log)
{
    if (!columns.hasOnlyOrdinary())
    {
        /// We don't allow special columns.
        throw Exception(ErrorCodes::BAD_ARGUMENTS,
            "Special columns like MATERIALIZED, ALIAS or EPHEMERAL are not supported for {} storage.",
            configuration.getTypeName());
    }

    /// If schema validation parameters are not provided, skip schema consistency check.
    if (!object_storage || !config_ptr || !format_settings || !sample_path || !context
        || !hive_partition_columns_to_read_from_file_path || !columns_in_table_or_function_definition || !log)
        return;

    /// We don't need to process data lakes because tables may have "schema evolution" feature.
    /// We don't check csv and tsv formats because they change column names.
    if (need_resolve_columns_or_format
        || configuration.isDataLakeConfiguration()
        || columns_in_table_or_function_definition->empty()
        || is_table_function
        || configuration.format == "CSV"
        || configuration.format == "TSV"
        || mode != LoadingStrictnessLevel::CREATE
        || do_lazy_init)
        return;

    /// Verify that explicitly specified columns exist in the schema inferred from data.
    String sample_path_schema = *sample_path;
    std::optional<ColumnsDescription> schema_file;
    try
    {
        schema_file = StorageObjectStorage::resolveSchemaFromData(
            object_storage,
            config_ptr,
            *format_settings,
            sample_path_schema,
            context);
    }
    catch (...)
    {
        tryLogCurrentException(log, "while verifying schema consistency", LogsLevel::debug);
    }
    if (schema_file)
    {
        std::unordered_set<String> hive_partitioning_columns;
        for (const auto & column_name : hive_partition_columns_to_read_from_file_path->getNames())
            hive_partitioning_columns.insert(column_name);
        for (const auto & column : *columns_in_table_or_function_definition)
            if (!schema_file->tryGet(column.name) && !hive_partitioning_columns.contains(column.name))

Review comment (suggestion):
Hm, too many arguments in `validateColumns`, don't you think?
You can reduce number of passed arguments here by passing a single bool flag `validate_schema_with_remote` (or any other name) instead of `is_table_function`, `do_lazy_init`, `need_resolve_columns_or_format`, `mode`, `columns_in_table_or_function_definition`...
```suggestion
    if (!validate_schema_with_remote
        || configuration.format == "CSV"
        || configuration.format == "TSV")
```

and passing `validateSchema(..., /* validate_schema_with_remote*/!is_table_function && !do_lazy_init && !configuration.isDataLakeConfiguration() && !columns_in_table_or_function_definition->empty() && mode == LoadingStrictnessLevel::CREATE)`

Code after:
    if (!columns.hasOnlyOrdinary())
    {
        /// We don't allow special columns.
        throw Exception(ErrorCodes::BAD_ARGUMENTS,
            "Special columns like MATERIALIZED, ALIAS or EPHEMERAL are not supported for {} storage.",
            configuration ? configuration->getTypeName() : "object storage");
    }

    /// If schema validation parameters are not provided, skip schema consistency check.
    /// validateColumns is only called with full arguments from StorageObjectStorage when
    /// resolveSchemaAndFormat was not used (validate_schema_with_remote == true).
    if (!object_storage || !configuration || !format_settings || !sample_path || !context
        || !hive_partition_columns_to_read_from_file_path || !columns_in_table_or_function_definition || !log)
        return;

    /// We don't check csv and tsv formats because they change column names.
    if (!validate_schema_with_remote
        || configuration->format == "CSV"
        || configuration->format == "TSV")
        return;

    /// Verify that explicitly specified columns exist in the schema inferred from data.
    String sample_path_schema = *sample_path;
    std::optional<ColumnsDescription> schema_file;
    try
    {
        schema_file = StorageObjectStorage::resolveSchemaFromData(
            object_storage,
            configuration,
            *format_settings,
            sample_path_schema,
            context);
    }
    catch (...)
    {
        tryLogCurrentException(log, "while verifying schema consistency", LogsLevel::debug);
    }
    if (schema_file)
    {
        auto hive_partitioning_columns = hive_partition_columns_to_read_from_file_path->getNameSet();
        for (const auto & column : *columns_in_table_or_function_definition)
            if (!schema_file->tryGet(column.name) && !hive_partitioning_columns.contains(column.name))
            {
                String hive_columns;
                for (const auto & hive_column : hive_partitioning_columns)
                    hive_columns += hive_column + ";";
                throw Exception(ErrorCodes::BAD_ARGUMENTS, "Cannot find column {} in schema {}, hive columns {}", column.name, schema_file->toString(false), hive_columns);
            }
    }
}