public CompletableFuture<QueryResponse> query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings) {
        if (settings == null) {
            settings = new QuerySettings();
        }
        if (settings.getFormat() == null) {
            settings.setFormat(ClickHouseFormat.RowBinaryWithNamesAndTypes);
        }
        ClientStatisticsHolder clientStats = new ClientStatisticsHolder();
        clientStats.start(ClientMetrics.OP_DURATION);
        applyDefaults(settings);

        Supplier<QueryResponse> responseSupplier;

            if (queryParams != null) {
                settings.setOption("statement_params", queryParams);
            }
            final QuerySettings finalSettings = settings;
            responseSupplier = () -> {
                long startTime = System.nanoTime();
                // Selecting some node
                Endpoint selectedEndpoint = getNextAliveNode();
                RuntimeException lastException = null;
                for (int i = 0; i <= retries; i++) {
                    try {
                        ClassicHttpResponse httpResponse =
                                httpClientHelper.executeRequest(selectedEndpoint, finalSettings.getAllSettings(), lz4Factory, output -> {
                                    output.write(sqlQuery.getBytes(StandardCharsets.UTF_8));
                                    output.close();
                                });

                        // Check response
                        if (httpResponse.getCode() == HttpStatus.SC_SERVICE_UNAVAILABLE) {
                            LOG.warn("Failed to get response. Server returned {}. Retrying. (Duration: {})", System.nanoTime() - startTime, httpResponse.getCode());
                            selectedEndpoint = getNextAliveNode();
                            continue;
                        }

                        OperationMetrics metrics = new OperationMetrics(clientStats);
                        String summary = HttpAPIClientHelper.getHeaderVal(httpResponse
                                .getFirstHeader(ClickHouseHttpProto.HEADER_SRV_SUMMARY), "{}");
                        ProcessParser.parseSummary(summary, metrics);
                        String queryId = HttpAPIClientHelper.getHeaderVal(httpResponse
                                .getFirstHeader(ClickHouseHttpProto.HEADER_QUERY_ID), finalSettings.getQueryId());
                        metrics.setQueryId(queryId);
                        metrics.operationComplete();
                        Header formatHeader = httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_FORMAT);
                        ClickHouseFormat responseFormat = finalSettings.getFormat();
                        if (formatHeader != null) {
                            responseFormat = ClickHouseFormat.valueOf(formatHeader.getValue());
                        }

                        return new QueryResponse(httpResponse, responseFormat, finalSettings, metrics);

                    } catch (Exception e) {
                        lastException = httpClientHelper.wrapException(String.format("Query request failed (Attempt: %s/%s - Duration: %s)",
                                (i + 1), (retries + 1), System.nanoTime() - startTime), e);
                        if (httpClientHelper.shouldRetry(e, finalSettings.getAllSettings())) {
                            LOG.warn("Retrying.", e);
                            selectedEndpoint = getNextAliveNode();
                        } else {
                            throw lastException;
                        }
                    }
                }

                throw new ClientException("Query request failed after attempts: " + (retries + 1) + " - Duration: " + (System.nanoTime() - startTime), lastException);
            };

        return runAsyncOperation(responseSupplier, settings.getAllSettings());
    }
<p>Sends SQL query to server with parameters. The map `queryParams` should contain keys that
match the placeholders in the SQL query.</p>
<p>For a parametrized query like:</p>
<pre>{@code
SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}
}
</pre>

<p>Code to set the queryParams would be:</p>
<pre>{@code
     Map<String, Object> queryParams = new HashMap<>();
     queryParams.put("id", 1);
     queryParams.put("phrase", "hello");
     }
</pre>

<b>Notes:</b>
<ul>
<li>Server response format can be specified thru {@code settings} or in SQL query.</li>
<li>If specified in both, the {@code sqlQuery} will take precedence.</li>
</ul>

@param sqlQuery - complete SQL query.
@param settings - query operation settings.
@param queryParams - query parameters that are sent to the server. (Optional)
@return {@code CompletableFuture<QueryResponse>} - a promise to query response.
client-v2/src/main/java/com/clickhouse/client/api/Client.java