**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. 
if (send_external_tables)
        sendExternalTables(parsed_query
    /// Receive description of table structure.
    Block sample;
    ColumnsDescription columns_description;
    if (receiveSampleBlock(sample, columns_description, parsed_query))
    {
        /// If structure was received (thus, server has not thrown an exception),
        /// send our data with that structure.
        sendData(sample, columns_description, parsed_query
        receiveEndOfQuery(
    }
}
void ClientBase::sendData(Block & sample, const ColumnsDescription & columns_description, ASTPtr parsed_query)
{
    /// Get columns description from variable or (if it was empty) create it from sample.
    auto columns_description_for_query = columns_description.empty() ? ColumnsDescription(sample.getNamesAndTypesList()) : columns_description;
    if (columns_description_for_query.empty())
    {
        throw Exception(ErrorCodes::LOGICAL_ERROR, "Column description is empty and it can't be built from sample from table. Cannot execute query."
    }
    /// If INSERT data must be sent.
    rsed_query->as<ASTInsertQuery>(
    if (!parsed_insert_query)
        return;
    if (need_render_progress)
    {
        /// Set total_bytes_to_read for current fd.
        FileProgress file_progress(0, std_in.size()
        progress_indication.updateProgress(Progress(file_progress)