**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. 
{
        StringRef name;
        StringRef host_name;
        UInt64 thread_id;
        bool operator<(const Id & rhs) const
        {
            return std::tie(name, host_name, thread_id)
                 < std::tie(rhs.name, rhs.host_name, rhs.thread_id
        }
    };
    std::map<Id, UInt64> rows_by_name;
    for (size_t src_row = 0; src_row < src.rows( ++src_row)
    {
        Id id{
            src_column_name.getDataAt(src_row),
            src_column_host_name.getDataAt(src_row),
            src_array_thread_id[src_row],
        };
        rows_by_name[id] = src_row;
    }
    /// Merge src into dst.
    for (sizw < dst_rows; ++dst_row)
    {
        Id id{
            dst_column_name.getDataAt(dst_row),
            dst_column_host_name.getDataAt(dst_row),
            dst_array_thread_id[dst_row],
        };
        if (auto it = rows_by_name.find(id it != rows_by_name.end())
        {