/**
   * Explain query.
   *
   * @param sql the sql
   * @return the string
   * @throws LensAPIException
   * @throws UnsupportedEncodingException the unsupported encoding exception
   */
  @CliCommand(
      value = "query explain",
      help =
          "Explain execution plan of query <query-string>. "
              + "Can optionally save the plan to a file by providing <save_location>")
  public String explainQuery(
      @CliOption(
              key = {"", "query"},
              mandatory = true,
              help = "<query-string>")
          String sql,
      @CliOption(
              key = {"save_location"},
              mandatory = false,
              help = "<save_location>")
          final File path)
      throws IOException, LensAPIException {
    PrettyPrintable cliOutput;

    try {
      QueryPlan plan = getClient().getQueryPlan(sql).getData();
      if (path != null && StringUtils.isNotBlank(path.getPath())) {
        String validPath = getValidPath(path, false, false);
        try (OutputStreamWriter osw =
            new OutputStreamWriter(new FileOutputStream(validPath), Charset.defaultCharset())) {
          osw.write(plan.getPlanString());
        }
        return "Saved to " + validPath;
      }
      return plan.getPlanString();
    } catch (final LensAPIException e) {
      BriefError briefError = new BriefError(e.getLensAPIErrorCode(), e.getLensAPIErrorMessage());
      cliOutput =
          new IdBriefErrorTemplate(
              IdBriefErrorTemplateKey.REQUEST_ID, e.getLensAPIRequestId(), briefError);
    } catch (final LensBriefErrorException e) {
      cliOutput = e.getIdBriefErrorTemplate();
    }
    return cliOutput.toPrettyString();
  }
 /**
  * Gets the query results.
  *
  * @param qh the qh
  * @return the query results
  */
 @CliCommand(
     value = "query results",
     help =
         "get results of query with query handle <query_handle>. "
             + DEFAULT_QUERY_HANDLE_DESCRIPTION
             + "If async is false then wait till the query execution is completed, it's by default true. "
             + "Can optionally save the results to a file by providing <save_location>.")
 public String getQueryResults(
     @CliOption(
             key = {"", "query_handle"},
             mandatory = false,
             help = "<query_handle>")
         String qh,
     @CliOption(
             key = {"save_location"},
             mandatory = false,
             help = "<save_location>")
         final File path,
     @CliOption(
             key = {"async"},
             mandatory = false,
             unspecifiedDefaultValue = "true",
             help = "<async>")
         boolean async) {
   qh = getOrDefaultQueryHandleString(qh);
   QueryHandle queryHandle = new QueryHandle(UUID.fromString(qh));
   LensClient.LensClientResultSetWithStats results;
   String location = path != null ? path.getPath() : null;
   try {
     if (StringUtils.isNotBlank(location)) {
       location = getValidPath(path, true, true);
       Response response = getClient().getHttpResults(queryHandle);
       if (response.getStatus() == Response.Status.OK.getStatusCode()) {
         String disposition = (String) response.getHeaders().get("content-disposition").get(0);
         String fileName = disposition.split("=")[1].trim();
         location = getValidPath(new File(location + File.separator + fileName), false, false);
         try (InputStream stream = response.readEntity(InputStream.class);
             FileOutputStream outStream = new FileOutputStream(new File(location))) {
           IOUtils.copy(stream, outStream);
         }
         return "Saved to " + location;
       } else {
         if (async) {
           results = getClient().getAsyncResults(queryHandle);
         } else {
           results = getClient().getSyncResults(queryHandle);
         }
         if (results.getResultSet() == null) {
           return "Resultset not yet available";
         } else if (results.getResultSet().getResult() instanceof InMemoryQueryResult) {
           location =
               getValidPath(new File(location + File.separator + qh + ".csv"), false, false);
           try (OutputStreamWriter osw =
               new OutputStreamWriter(new FileOutputStream(location), Charset.defaultCharset())) {
             osw.write(formatResultSet(results));
           }
           return "Saved to " + location;
         } else {
           return "Can't download the result because it's available in driver's persistence.\n"
               + formatResultSet(results);
         }
       }
     } else if (async) {
       return formatResultSet(getClient().getAsyncResults(queryHandle));
     } else {
       return formatResultSet(getClient().getSyncResults(queryHandle));
     }
   } catch (Throwable t) {
     return t.getMessage();
   }
 }