**Use case**

This works:

```
SELECT * FROM hits_100m_obfuscated INTO OUTFILE 'hits.csv' FORMAT CSV
```

But I want this:

```
SELECT * FROM hits_100m_obfuscated INTO OUTFILE 'hits.csv'
```

**Describe the solution you'd like**

Every format can register file extension(s) in format factory.
If format is not specified explicitly, we can detect it automatically by file extension.
It should work for compressed files `hits.csv.gz` as well.

The following extensions should be supported at least:
csv, tsv, parquet, orc, native, json, ndjson, xml, md, avro

**Addition details**

Let's also support omitting the format argument for `file`, `url`, `s3`, `hdfs` table functions. 
throw Exception("No data to insert", ErrorCodes::NO_DATA_TO_INSERT
}
void ClientBase::sendDataFrom(ReadBuffer & buf, Block & sample, const ColumnsDescription & columns_description, ASTPtr parsed_query)
{
    String current_format = insert_format;
    /// Data format can be specified in the INSERT query.
    if (const auto * insert = parsed_query->as<ASTInsertQuery>())
    {
        if (!insert->format.empty())
            current_format = insert->format;
    }
    auto source = global_context->getInputFormat(current_format, buf, sample, insert_format_max_block_size
    Pipe pipe(source
    if (columns_description.hasDefaults())
    {
        pipe.addSimpleTransform([&](const Block & header)
        {
            return std::make_shared<AddingDefaultsTransform>(header, columns_description, *source, global_context
        }
    }
    sendDataFromPipe(std::move(pipe), parsed_query
}
void ClientBase::sendDataFromPipe(Pipe&& pipe, ASTPtr parsed_query)
{
    QueryPipeline pipeline(std::move(pipe)
    PullingAsyncPipelineExecutor executor(pipeline
    Block block;
    while (executor.pull(block))
    {
        /// Check if server send Log packet