@Override
  public AbstractQueryResult executePreparedQuery(
      String sql,
      ParameterHolder[] parameters,
      PrepareResult prepareResult,
      MariaDbType[] parameterTypeHeader,
      boolean isStreaming)
      throws QueryException {
    this.moreResults = false;
    try {
      int parameterCount = parameters.length;
      // send binary data in a separate stream
      for (int i = 0; i < parameterCount; i++) {
        if (parameters[i].isLongData()) {
          SendPrepareParameterPacket sendPrepareParameterPacket =
              new SendPrepareParameterPacket(
                  i, (LongDataParameterHolder) parameters[i], prepareResult.statementId, charset);
          sendPrepareParameterPacket.send(writer);
        }
      }
      // send execute query
      SendExecutePrepareStatementPacket packet =
          new SendExecutePrepareStatementPacket(
              prepareResult.statementId, parameters, parameterCount, parameterTypeHeader);
      packet.send(writer);

    } catch (MaxAllowedPacketException e) {
      if (e.isMustReconnect()) {
        connect();
      }
      throw new QueryException(
          "Could not send query: " + e.getMessage(),
          -1,
          ExceptionMapper.SqlStates.INTERRUPTED_EXCEPTION.getSqlState(),
          e);
    } catch (IOException e) {
      throw new QueryException(
          "Could not send query: " + e.getMessage(),
          -1,
          ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
          e);
    }

    try {
      return getResult(sql, isStreaming, true);
    } catch (QueryException qex) {
      if (qex.getCause() instanceof SocketTimeoutException) {
        throw new QueryException(
            "Connection timed out",
            -1,
            ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
            qex);
      } else {
        throw qex;
      }
    }
  }
  /**
   * Execute queries.
   *
   * @param queries queries list
   * @param streaming is streaming flag
   * @param isRewritable is rewritable flag
   * @param rewriteOffset rewriteoffset
   * @return queryResult
   * @throws QueryException exception
   */
  public AbstractQueryResult executeBatch(
      final List<Query> queries, boolean streaming, boolean isRewritable, int rewriteOffset)
      throws QueryException {
    for (Query query : queries) {
      query.validate();
    }

    this.moreResults = false;
    final SendTextQueryPacket packet =
        new SendTextQueryPacket(queries, isRewritable, rewriteOffset);
    try {
      packet.send(writer);
    } catch (MaxAllowedPacketException e) {
      if (e.isMustReconnect()) {
        connect();
      }
      throw new QueryException(
          "Could not send query: " + e.getMessage(),
          -1,
          ExceptionMapper.SqlStates.INTERRUPTED_EXCEPTION.getSqlState(),
          e);
    } catch (IOException e) {
      throw new QueryException(
          "Could not send query: " + e.getMessage(),
          -1,
          ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
          e);
    }

    try {
      return getResult(queries, streaming, false);
    } catch (QueryException qex) {
      if (qex.getCause() instanceof SocketTimeoutException) {
        throw new QueryException(
            "Connection timed out",
            -1,
            ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
            qex);
      } else {
        throw qex;
      }
    }
  }
 private int sendQuery(SendTextQueryPacket packet) throws QueryException {
   try {
     return packet.send(writer);
   } catch (MaxAllowedPacketException e) {
     if (e.isMustReconnect()) {
       connect();
     }
     throw new QueryException(
         "Could not send query: " + e.getMessage(),
         -1,
         ExceptionMapper.SqlStates.INTERRUPTED_EXCEPTION.getSqlState(),
         e);
   } catch (IOException e) {
     throw new QueryException(
         "Could not send query: " + e.getMessage(),
         -1,
         ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
         e);
   }
 }
  @Override
  public AbstractQueryResult getResult(Object queriesObj, boolean streaming, boolean binaryProtocol)
      throws QueryException {
    RawPacket rawPacket = null;
    AbstractResultPacket resultPacket;
    try {
      rawPacket = packetFetcher.getReusableRawPacket();
      resultPacket = ReadResultPacketFactory.createResultPacket(rawPacket.getByteBuffer());

      if (resultPacket.getResultType() == AbstractResultPacket.ResultType.LOCALINFILE) {
        // Server request the local file (LOCAL DATA LOCAL INFILE)
        // We do accept general URLs, too. If the localInfileStream is
        // set, use that.

        InputStream is;
        if (localInfileInputStream == null) {
          if (!getUrlParser().getOptions().allowLocalInfile) {

            writer.writeEmptyPacket(rawPacket.getPacketSeq() + 1);
            throw new QueryException(
                "Usage of LOCAL INFILE is disabled. To use it enable it via the connection property allowLocalInfile=true",
                -1,
                ExceptionMapper.SqlStates.FEATURE_NOT_SUPPORTED.getSqlState());
          }
          LocalInfilePacket localInfilePacket = (LocalInfilePacket) resultPacket;
          String localInfile = localInfilePacket.getFileName();

          try {
            URL url = new URL(localInfile);
            is = url.openStream();
          } catch (IOException ioe) {
            try {
              is = new FileInputStream(localInfile);
            } catch (FileNotFoundException f) {
              writer.writeEmptyPacket(rawPacket.getPacketSeq() + 1);
              ReadResultPacketFactory.createResultPacket(packetFetcher);
              throw new QueryException("Could not send file : " + f.getMessage(), -1, "22000", f);
            }
          }
        } else {
          is = localInfileInputStream;
          localInfileInputStream = null;
        }

        writer.sendFile(is, rawPacket.getPacketSeq() + 1);
        is.close();
        resultPacket = ReadResultPacketFactory.createResultPacket(packetFetcher);
      }
    } catch (SocketTimeoutException ste) {
      this.close();
      throw new QueryException(
          "Could not read resultset: " + ste.getMessage(),
          -1,
          ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
          ste);
    } catch (IOException e) {
      try {
        if (writer != null && rawPacket != null) {
          writer.writeEmptyPacket(rawPacket.getPacketSeq() + 1);
          ReadResultPacketFactory.createResultPacket(packetFetcher);
        }
      } catch (IOException ee) {
      }
      throw new QueryException(
          "Could not read resultset: " + e.getMessage(),
          -1,
          ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
          e);
    }

    switch (resultPacket.getResultType()) {
      case ERROR:
        this.moreResults = false;
        this.hasWarnings = false;
        ErrorPacket ep = (ErrorPacket) resultPacket;
        throw new QueryException(ep.getMessage(), ep.getErrorNumber(), ep.getSqlState());

      case OK:
        final OkPacket okpacket = (OkPacket) resultPacket;
        serverStatus = okpacket.getServerStatus();
        this.moreResults = ((serverStatus & ServerStatus.MORE_RESULTS_EXISTS) != 0);
        this.hasWarnings = (okpacket.getWarnings() > 0);
        final AbstractQueryResult updateResult =
            new UpdateResult(
                okpacket.getAffectedRows(),
                okpacket.getWarnings(),
                okpacket.getMessage(),
                okpacket.getInsertId());
        return updateResult;
      case RESULTSET:
        this.hasWarnings = false;
        ResultSetPacket resultSetPacket = (ResultSetPacket) resultPacket;
        try {
          return this.createQueryResult(resultSetPacket, streaming, binaryProtocol);
        } catch (IOException e) {

          throw new QueryException(
              "Could not read result set: " + e.getMessage(),
              -1,
              ExceptionMapper.SqlStates.CONNECTION_EXCEPTION.getSqlState(),
              e);
        }
      default:
        throw new QueryException(
            "Could not parse result",
            (short) -1,
            ExceptionMapper.SqlStates.INTERRUPTED_EXCEPTION.getSqlState());
    }
  }