@Override
 public PostgresStatementResult execute(
     PostgresQueryContext context, QueryBindings bindings, int maxrows) throws IOException {
   PostgresServerSession server = context.getServer();
   server.getSessionMonitor().countEvent(StatementTypes.OTHER_STMT);
   PostgresMessenger messenger = server.getMessenger();
   ServerValueEncoder encoder = server.getValueEncoder();
   int nrows = 0;
   for (String row : explanation) {
     messenger.beginMessage(PostgresMessages.DATA_ROW_TYPE.code());
     messenger.writeShort(1);
     ByteArrayOutputStream bytes = encoder.encodePObject(row, colType, false);
     messenger.writeInt(bytes.size());
     messenger.writeByteStream(bytes);
     messenger.sendMessage();
     nrows++;
     if ((maxrows > 0) && (nrows >= maxrows)) break;
   }
   return commandComplete("EXPLAIN " + nrows, nrows);
 }
 @Override
 public void sendDescription(PostgresQueryContext context, boolean always, boolean params)
     throws IOException {
   PostgresServerSession server = context.getServer();
   PostgresMessenger messenger = server.getMessenger();
   if (params) {
     messenger.beginMessage(PostgresMessages.PARAMETER_DESCRIPTION_TYPE.code());
     messenger.writeShort(0);
     messenger.sendMessage();
   }
   messenger.beginMessage(PostgresMessages.ROW_DESCRIPTION_TYPE.code());
   messenger.writeShort(1);
   messenger.writeString(colName); // attname
   messenger.writeInt(0); // attrelid
   messenger.writeShort(0); // attnum
   messenger.writeInt(colType.getOid()); // atttypid
   messenger.writeShort(colType.getLength()); // attlen
   messenger.writeInt(colType.getModifier()); // atttypmod
   messenger.writeShort(0);
   messenger.sendMessage();
 }
 @Override
 public PostgresStatement finishGenerating(
     PostgresServerSession server,
     String sql,
     StatementNode stmt,
     List<ParameterNode> params,
     int[] paramTypes) {
   ExplainPlanContext context = new ExplainPlanContext(compiler, new PostgresQueryContext(server));
   ExplainStatementNode explainStmt = (ExplainStatementNode) stmt;
   StatementNode innerStmt = explainStmt.getStatement();
   if (params == null) params = new ParameterFinder().find(innerStmt);
   Explainable explainable;
   if (innerStmt instanceof CallStatementNode) {
     explainable =
         PostgresCallStatementGenerator.explainable(
             server, (CallStatementNode) innerStmt, params, paramTypes);
   } else {
     BasePlannable result = compiler.compile((DMLStatementNode) innerStmt, params, context);
     explainable = result.getPlannable();
   }
   List<String> explain;
   if (compiler instanceof PostgresJsonCompiler) {
     JsonFormatter f = new JsonFormatter();
     explain =
         Collections.singletonList(
             f.format(explainable.getExplainer(context.getExplainContext())));
   } else {
     DefaultFormatter.LevelOfDetail detail;
     switch (explainStmt.getDetail()) {
       case BRIEF:
         detail = DefaultFormatter.LevelOfDetail.BRIEF;
         break;
       default:
       case NORMAL:
         detail = DefaultFormatter.LevelOfDetail.NORMAL;
         break;
       case VERBOSE:
         detail = DefaultFormatter.LevelOfDetail.VERBOSE;
         break;
     }
     DefaultFormatter f = new DefaultFormatter(server.getDefaultSchemaName(), detail);
     explain = f.format(explainable.getExplainer(context.getExplainContext()));
   }
   init(explain);
   compiler = null;
   return this;
 }