static CompletableFuture<List<ClickHouseResponseSummary>> send(ClickHouseNode server, String sql,
            ClickHouseValue[] templates, Object[]... params) {
        int len = templates != null ? templates.length : 0;
        int size = params != null ? params.length : 0;
        if (len == 0 || size == 0) {
            throw new IllegalArgumentException("Non-empty templates and parameters are required");
        }

        // in case the protocol is ANY
        final ClickHouseNode theServer = server.probe();

        return submit(() -> {
            List<ClickHouseResponseSummary> list = new ArrayList<>(size);

            // set async to false so that we don't have to create additional thread
            try (ClickHouseClient client = ClickHouseClient.builder()
                    .nodeSelector(ClickHouseNodeSelector.of(theServer.getProtocol()))
                    .option(ClickHouseClientOption.ASYNC, false).build()) {
                // format doesn't matter here as we only need a summary
                ClickHouseRequest<?> request = client.read(theServer).format(ClickHouseFormat.RowBinary).query(sql);
                for (int i = 0; i < size; i++) {
                    Object[] o = params[i];
                    String[] arr = new String[len];
                    for (int j = 0, olen = o == null ? 0 : o.length; j < len; j++) {
                        ClickHouseValue v = templates[j];
                        if (j < olen) {
                            arr[j] = v != null ? v.update(o[j]).toSqlExpression()
                                    : ClickHouseValues.convertToSqlExpression(o[j]);
                        } else {
                            arr[j] = v != null ? v.resetToNullOrEmpty().toSqlExpression() : ClickHouseValues.NULL_EXPR;
                        }
                    }
                    try (ClickHouseResponse resp = request.params(arr).executeAndWait()) {
                        list.add(resp.getSummary());
                    }
                }
            }

            return list;
        });
    }
Sends SQL query along with template objects and raw parameters to specified
server.

@param server    non-null server to connect to
@param sql       non-null SQL query
@param templates non-empty template objects to stringify parameters
@param params    non-empty raw parameters
@return list of {@link ClickHouseResponseSummary} one for each execution
@throws IllegalArgumentException if no named parameter in the query, or
                                 templates or params is null or empty
@throws CompletionException      when error occurred during execution
clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java