You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2015/12/02 19:06:07 UTC

[1/3] calcite git commit: [CALCITE-989] Add server's address in each response

Repository: calcite
Updated Branches:
  refs/heads/master 81b487684 -> 3be816f45


http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java
index a8b76d8..9565598 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java
@@ -21,6 +21,7 @@ import org.apache.calcite.avatica.NoSuchConnectionException;
 import org.apache.calcite.avatica.remote.Service.ErrorResponse;
 import org.apache.calcite.avatica.remote.Service.Request;
 import org.apache.calcite.avatica.remote.Service.Response;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import java.io.IOException;
 
@@ -33,6 +34,7 @@ import java.io.IOException;
 public abstract class AbstractHandler<T> implements Handler<T> {
   private static final String NULL_EXCEPTION_MESSAGE = "(null exception message)";
   protected final Service service;
+  private RpcMetadataResponse metadata = null;
 
   public AbstractHandler(Service service) {
     this.service = service;
@@ -78,7 +80,7 @@ public abstract class AbstractHandler<T> implements Handler<T> {
       errorMsg = getCausalChain(e);
     }
 
-    return new ErrorResponse(e, errorMsg, errorCode, sqlState, severity);
+    return new ErrorResponse(e, errorMsg, errorCode, sqlState, severity, metadata);
   }
 
   /**
@@ -143,6 +145,11 @@ public abstract class AbstractHandler<T> implements Handler<T> {
     }
     return sb.toString();
   }
+
+  @Override
+  public void setRpcMetadata(RpcMetadataResponse metadata) {
+    this.metadata = metadata;
+  }
 }
 
 // End AbstractHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
index f15e0e7..ecb4adb 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
@@ -29,6 +29,8 @@ import java.util.List;
  */
 public abstract class AbstractService implements Service {
 
+  private RpcMetadataResponse rpcMetadata = null;
+
   /**
    * Represents the serialization of the data over a transport.
    */
@@ -102,7 +104,7 @@ public abstract class AbstractService implements Service {
     if (statement == response.statement) {
       return response;
     }
-    return new PrepareResponse(statement);
+    return new PrepareResponse(statement, rpcMetadata);
   }
 
   Meta.StatementHandle finagle(Meta.StatementHandle h) {
@@ -126,7 +128,7 @@ public abstract class AbstractService implements Service {
       return r;
     }
     return new ResultSetResponse(r.connectionId, r.statementId, r.ownStatement,
-        signature, r.firstFrame, r.updateCount);
+        signature, r.firstFrame, r.updateCount, rpcMetadata);
   }
 
   ExecuteResponse finagle(ExecuteResponse r) {
@@ -145,7 +147,13 @@ public abstract class AbstractService implements Service {
     if (changeCount == 0) {
       return r;
     }
-    return new ExecuteResponse(results, r.missingStatement);
+    return new ExecuteResponse(results, r.missingStatement, rpcMetadata);
+  }
+
+  @Override
+  public void setRpcMetadata(RpcMetadataResponse metadata) {
+    // OK if this is null
+    this.rpcMetadata = metadata;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
index f2cfeb6..e3ad07f 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.avatica.remote;
 
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
 import java.util.Objects;
 
 /**
@@ -53,6 +55,13 @@ public interface Handler<T> {
   }
 
   HandlerResponse<T> apply(T request);
+
+  /**
+   * Sets some general server information to return to the client in all responses.
+   *
+   * @param metadata Server-wide information
+   */
+  void setRpcMetadata(RpcMetadataResponse metadata);
 }
 
 // End Handler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
index ff75af5..c4a5893 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
@@ -24,6 +24,7 @@ import org.apache.calcite.avatica.NoSuchStatementException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Implementation of {@link Service} that talks to a local {@link Meta}.
@@ -31,10 +32,16 @@ import java.util.List;
 public class LocalService implements Service {
   final Meta meta;
 
+  private RpcMetadataResponse serverLevelRpcMetadata;
+
   public LocalService(Meta meta) {
     this.meta = meta;
   }
 
+  @Override public void setRpcMetadata(RpcMetadataResponse serverLevelRpcMetadata) {
+    this.serverLevelRpcMetadata = Objects.requireNonNull(serverLevelRpcMetadata);
+  }
+
   private static <E> List<E> list(Iterable<E> iterable) {
     if (iterable instanceof List) {
       return (List<E>) iterable;
@@ -51,7 +58,7 @@ public class LocalService implements Service {
     if (resultSet.updateCount != -1) {
       return new ResultSetResponse(resultSet.connectionId,
           resultSet.statementId, resultSet.ownStatement, null, null,
-          resultSet.updateCount);
+          resultSet.updateCount, serverLevelRpcMetadata);
     }
 
     Meta.Signature signature = resultSet.signature;
@@ -98,7 +105,7 @@ public class LocalService implements Service {
     }
 
     return new ResultSetResponse(resultSet.connectionId, resultSet.statementId,
-        resultSet.ownStatement, signature, frame, updateCount);
+        resultSet.ownStatement, signature, frame, updateCount, serverLevelRpcMetadata);
   }
 
   private List<List<Object>> list2(Meta.MetaResultSet resultSet) {
@@ -169,7 +176,7 @@ public class LocalService implements Service {
         new Meta.ConnectionHandle(request.connectionId);
     final Meta.StatementHandle h =
         meta.prepare(ch, request.sql, request.maxRowCount);
-    return new PrepareResponse(h);
+    return new PrepareResponse(h, serverLevelRpcMetadata);
   }
 
   public ExecuteResponse apply(PrepareAndExecuteRequest request) {
@@ -197,10 +204,10 @@ public class LocalService implements Service {
       for (Meta.MetaResultSet metaResultSet : executeResult.resultSets) {
         results.add(toResponse(metaResultSet));
       }
-      return new ExecuteResponse(results, false);
+      return new ExecuteResponse(results, false, serverLevelRpcMetadata);
     } catch (NoSuchStatementException e) {
       // The Statement doesn't exist anymore, bubble up this information
-      return new ExecuteResponse(null, true);
+      return new ExecuteResponse(null, true, serverLevelRpcMetadata);
     }
   }
 
@@ -212,12 +219,12 @@ public class LocalService implements Service {
           meta.fetch(h,
               request.offset,
               request.fetchMaxRowCount);
-      return new FetchResponse(frame, false, false);
+      return new FetchResponse(frame, false, false, serverLevelRpcMetadata);
     } catch (NullPointerException | NoSuchStatementException e) {
       // The Statement doesn't exist anymore, bubble up this information
-      return new FetchResponse(null, true, true);
+      return new FetchResponse(null, true, true, serverLevelRpcMetadata);
     } catch (MissingResultsException e) {
-      return new FetchResponse(null, false, true);
+      return new FetchResponse(null, false, true, serverLevelRpcMetadata);
     }
   }
 
@@ -230,9 +237,9 @@ public class LocalService implements Service {
       for (Meta.MetaResultSet metaResultSet : executeResult.resultSets) {
         results.add(toResponse(metaResultSet));
       }
-      return new ExecuteResponse(results, false);
+      return new ExecuteResponse(results, false, serverLevelRpcMetadata);
     } catch (NoSuchStatementException e) {
-      return new ExecuteResponse(null, true);
+      return new ExecuteResponse(null, true, serverLevelRpcMetadata);
     }
   }
 
@@ -240,28 +247,28 @@ public class LocalService implements Service {
     final Meta.ConnectionHandle ch =
         new Meta.ConnectionHandle(request.connectionId);
     final Meta.StatementHandle h = meta.createStatement(ch);
-    return new CreateStatementResponse(h.connectionId, h.id);
+    return new CreateStatementResponse(h.connectionId, h.id, serverLevelRpcMetadata);
   }
 
   public CloseStatementResponse apply(CloseStatementRequest request) {
     final Meta.StatementHandle h = new Meta.StatementHandle(
         request.connectionId, request.statementId, null);
     meta.closeStatement(h);
-    return new CloseStatementResponse();
+    return new CloseStatementResponse(serverLevelRpcMetadata);
   }
 
   public OpenConnectionResponse apply(OpenConnectionRequest request) {
     final Meta.ConnectionHandle ch =
         new Meta.ConnectionHandle(request.connectionId);
     meta.openConnection(ch, request.info);
-    return new OpenConnectionResponse();
+    return new OpenConnectionResponse(serverLevelRpcMetadata);
   }
 
   public CloseConnectionResponse apply(CloseConnectionRequest request) {
     final Meta.ConnectionHandle ch =
         new Meta.ConnectionHandle(request.connectionId);
     meta.closeConnection(ch);
-    return new CloseConnectionResponse();
+    return new CloseConnectionResponse(serverLevelRpcMetadata);
   }
 
   public ConnectionSyncResponse apply(ConnectionSyncRequest request) {
@@ -269,13 +276,13 @@ public class LocalService implements Service {
         new Meta.ConnectionHandle(request.connectionId);
     final Meta.ConnectionProperties connProps =
         meta.connectionSync(ch, request.connProps);
-    return new ConnectionSyncResponse(connProps);
+    return new ConnectionSyncResponse(connProps, serverLevelRpcMetadata);
   }
 
   public DatabasePropertyResponse apply(DatabasePropertyRequest request) {
     final Meta.ConnectionHandle ch =
         new Meta.ConnectionHandle(request.connectionId);
-    return new DatabasePropertyResponse(meta.getDatabaseProperties(ch));
+    return new DatabasePropertyResponse(meta.getDatabaseProperties(ch), serverLevelRpcMetadata);
   }
 
   public SyncResultsResponse apply(SyncResultsRequest request) {
@@ -284,10 +291,11 @@ public class LocalService implements Service {
     SyncResultsResponse response;
     try {
       // Set success on the cached statement
-      response = new SyncResultsResponse(meta.syncResults(h, request.state, request.offset), false);
+      response = new SyncResultsResponse(meta.syncResults(h, request.state, request.offset), false,
+          serverLevelRpcMetadata);
     } catch (NoSuchStatementException e) {
       // Tried to sync results on a statement which wasn't cached
-      response = new SyncResultsResponse(false, true);
+      response = new SyncResultsResponse(false, true, serverLevelRpcMetadata);
     }
 
     return response;

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
index b04980b..2fcb19a 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
@@ -55,15 +55,15 @@ public class MockProtobufService extends ProtobufService {
     mappings.put(
         new SchemasRequest(connectionId, null, null),
         // ownStatement=false just to avoid the extra close statement call.
-        new ResultSetResponse(null, 1, false, null, Meta.Frame.EMPTY, -1));
+        new ResultSetResponse(null, 1, false, null, Meta.Frame.EMPTY, -1, null));
 
     // Get the tables, no tables exist
     mappings.put(new TablesRequest(connectionId, null, null, null, Collections.<String>emptyList()),
         // ownStatement=false just to avoid the extra close statement call.
-        new ResultSetResponse(null, 150, false, null, Meta.Frame.EMPTY, -1));
+        new ResultSetResponse(null, 150, false, null, Meta.Frame.EMPTY, -1, null));
 
     // Create a statement, get back an id
-    mappings.put(new CreateStatementRequest("0"), new CreateStatementResponse("0", 1));
+    mappings.put(new CreateStatementRequest("0"), new CreateStatementResponse("0", 1, null));
 
     // Prepare and execute a query. Values and schema are returned
     mappings.put(
@@ -77,7 +77,7 @@ public class MockProtobufService extends ProtobufService {
                 null, null, Meta.CursorFactory.ARRAY, Meta.StatementType.SELECT),
             Meta.Frame.create(0, true,
                 Arrays.<Object>asList(new Object[] {1, "a"},
-                    new Object[] {null, "b"}, new Object[] {3, "c"})), -1));
+                    new Object[] {null, "b"}, new Object[] {3, "c"})), -1, null));
 
     // Prepare a query. Schema for results are returned, but no values
     mappings.put(
@@ -90,7 +90,7 @@ public class MockProtobufService extends ProtobufService {
                     MetaImpl.columnMetaData("C2", 1, String.class)),
                 null, Collections.<AvaticaParameter>emptyList(),
                 Meta.CursorFactory.ARRAY, Meta.StatementType.SELECT),
-            null, -1));
+            null, -1, null));
 
     mappings.put(
         new ColumnsRequest(connectionId, null, null, "my_table", null),
@@ -101,7 +101,7 @@ public class MockProtobufService extends ProtobufService {
                     MetaImpl.columnMetaData("ORDINAL_POSITION", 1, Long.class)), null,
                 Collections.<AvaticaParameter>emptyList(), Meta.CursorFactory.ARRAY, null),
             Meta.Frame.create(0, true,
-                Arrays.<Object>asList(new Object[] {new Object[]{"my_table", 10}})), -1));
+                Arrays.<Object>asList(new Object[] {new Object[]{"my_table", 10}})), -1, null));
 
     return Collections.unmodifiableMap(mappings);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufTranslationImpl.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufTranslationImpl.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufTranslationImpl.java
index 9c68beb..85d3a2b 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufTranslationImpl.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufTranslationImpl.java
@@ -45,9 +45,11 @@ import org.apache.calcite.avatica.proto.Responses.FetchResponse;
 import org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse;
 import org.apache.calcite.avatica.proto.Responses.PrepareResponse;
 import org.apache.calcite.avatica.proto.Responses.ResultSetResponse;
+import org.apache.calcite.avatica.proto.Responses.RpcMetadata;
 import org.apache.calcite.avatica.proto.Responses.SyncResultsResponse;
 import org.apache.calcite.avatica.remote.Service.Request;
 import org.apache.calcite.avatica.remote.Service.Response;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import com.google.protobuf.ByteString;
 import com.google.protobuf.InvalidProtocolBufferException;
@@ -144,6 +146,8 @@ public class ProtobufTranslationImpl implements ProtobufTranslation {
         new ResponseTranslator(ErrorResponse.parser(), new Service.ErrorResponse()));
     respParsers.put(SyncResultsResponse.class.getName(),
         new ResponseTranslator(SyncResultsResponse.parser(), new Service.SyncResultsResponse()));
+    respParsers.put(RpcMetadata.class.getName(),
+        new ResponseTranslator(RpcMetadata.parser(), new RpcMetadataResponse()));
 
     RESPONSE_PARSERS = Collections.unmodifiableMap(respParsers);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
index 473e96c..db87dff 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
@@ -69,6 +69,13 @@ public interface Service {
   ConnectionSyncResponse apply(ConnectionSyncRequest request);
   DatabasePropertyResponse apply(DatabasePropertyRequest request);
 
+  /**
+   * Sets server-level metadata for RPCs. This includes information that is static across all RPCs.
+   *
+   * @param metadata The server-level metadata.
+   */
+  void setRpcMetadata(RpcMetadataResponse metadata);
+
   /** Factory that creates a {@code Service}. */
   interface Factory {
     Service create(AvaticaConnection connection);
@@ -128,7 +135,8 @@ public interface Service {
       @JsonSubTypes.Type(value = DatabasePropertyResponse.class, name = "databaseProperties"),
       @JsonSubTypes.Type(value = ExecuteResponse.class, name = "executeResults"),
       @JsonSubTypes.Type(value = ErrorResponse.class, name = "error"),
-      @JsonSubTypes.Type(value = SyncResultsResponse.class, name = "syncResults") })
+      @JsonSubTypes.Type(value = SyncResultsResponse.class, name = "syncResults"),
+      @JsonSubTypes.Type(value = RpcMetadataResponse.class, name = "rpcMetadata") })
   abstract class Response {
     abstract Response deserialize(Message genericMsg);
     abstract Message serialize();
@@ -888,6 +896,7 @@ public interface Service {
     public final Meta.Signature signature;
     public final Meta.Frame firstFrame;
     public final long updateCount;
+    public final RpcMetadataResponse rpcMetadata;
 
     ResultSetResponse() {
       connectionId = null;
@@ -896,6 +905,7 @@ public interface Service {
       signature = null;
       firstFrame = null;
       updateCount = 0;
+      rpcMetadata = null;
     }
 
     @JsonCreator
@@ -905,13 +915,15 @@ public interface Service {
         @JsonProperty("ownStatement") boolean ownStatement,
         @JsonProperty("signature") Meta.Signature signature,
         @JsonProperty("firstFrame") Meta.Frame firstFrame,
-        @JsonProperty("updateCount") long updateCount) {
+        @JsonProperty("updateCount") long updateCount,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.connectionId = connectionId;
       this.statementId = statementId;
       this.ownStatement = ownStatement;
       this.signature = signature;
       this.firstFrame = firstFrame;
       this.updateCount = updateCount;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override ResultSetResponse deserialize(Message genericMsg) {
@@ -943,8 +955,13 @@ public interface Service {
         frame = Meta.Frame.fromProto(msg.getFirstFrame());
       }
 
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc, Responses.ResultSetResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
       return new ResultSetResponse(connectionId, msg.getStatementId(), msg.getOwnStatement(),
-          signature, frame, msg.getUpdateCount());
+          signature, frame, msg.getUpdateCount(), metadata);
     }
 
     @Override Responses.ResultSetResponse serialize() {
@@ -964,6 +981,10 @@ public interface Service {
         builder.setFirstFrame(firstFrame.toProto());
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.build();
     }
 
@@ -976,6 +997,7 @@ public interface Service {
       result = prime * result + ((signature == null) ? 0 : signature.hashCode());
       result = prime * result + statementId;
       result = prime * result + (int) (updateCount ^ (updateCount >>> 32));
+      result = prime * result + ((rpcMetadata == null) ? 0 : rpcMetadata.hashCode());
       return result;
     }
 
@@ -1010,6 +1032,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return ownStatement == other.ownStatement && statementId == other.statementId
             && updateCount == other.updateCount;
       }
@@ -1250,16 +1280,20 @@ public interface Service {
   class ExecuteResponse extends Response {
     public final List<ResultSetResponse> results;
     public boolean missingStatement = false;
+    public final RpcMetadataResponse rpcMetadata;
 
     ExecuteResponse() {
       results = null;
+      rpcMetadata = null;
     }
 
     @JsonCreator
     public ExecuteResponse(@JsonProperty("resultSets") List<ResultSetResponse> results,
-        @JsonProperty("missingStatement") boolean missingStatement) {
+        @JsonProperty("missingStatement") boolean missingStatement,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.results = results;
       this.missingStatement = missingStatement;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override ExecuteResponse deserialize(Message genericMsg) {
@@ -1269,6 +1303,7 @@ public interface Service {
       }
 
       Responses.ExecuteResponse msg = (Responses.ExecuteResponse) genericMsg;
+      final Descriptor desc = msg.getDescriptorForType();
 
       List<Responses.ResultSetResponse> msgResults = msg.getResultsList();
       List<ResultSetResponse> copiedResults = new ArrayList<>(msgResults.size());
@@ -1277,7 +1312,12 @@ public interface Service {
         copiedResults.add(ResultSetResponse.fromProto(msgResult));
       }
 
-      return new ExecuteResponse(copiedResults, msg.getMissingStatement());
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc, Responses.ExecuteResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new ExecuteResponse(copiedResults, msg.getMissingStatement(), metadata);
     }
 
     @Override Responses.ExecuteResponse serialize() {
@@ -1287,15 +1327,19 @@ public interface Service {
         builder.addResults(result.serialize());
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.setMissingStatement(missingStatement).build();
     }
 
     @Override public int hashCode() {
-      if (null == results) {
-        return 0;
-      }
-
-      return results.hashCode();
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((results == null) ? 0 : results.hashCode());
+      result = prime * result + ((rpcMetadata == null) ? 0 : rpcMetadata.hashCode());
+      return result;
     }
 
     @Override public boolean equals(Object o) {
@@ -1313,6 +1357,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != other.rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return true;
       }
 
@@ -1426,15 +1478,19 @@ public interface Service {
    * {@link org.apache.calcite.avatica.remote.Service.PrepareRequest}. */
   class PrepareResponse extends Response {
     public final Meta.StatementHandle statement;
+    public final RpcMetadataResponse rpcMetadata;
 
     PrepareResponse() {
       statement = null;
+      rpcMetadata = null;
     }
 
     @JsonCreator
     public PrepareResponse(
-        @JsonProperty("statement") Meta.StatementHandle statement) {
+        @JsonProperty("statement") Meta.StatementHandle statement,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.statement = statement;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override PrepareResponse deserialize(Message genericMsg) {
@@ -1444,8 +1500,14 @@ public interface Service {
       }
 
       Responses.PrepareResponse msg = (Responses.PrepareResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc, Responses.PrepareResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
 
-      return new PrepareResponse(Meta.StatementHandle.fromProto(msg.getStatement()));
+      return new PrepareResponse(Meta.StatementHandle.fromProto(msg.getStatement()), metadata);
     }
 
     @Override Responses.PrepareResponse serialize() {
@@ -1455,6 +1517,10 @@ public interface Service {
         builder.setStatement(statement.toProto());
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.build();
     }
 
@@ -1462,6 +1528,7 @@ public interface Service {
       final int prime = 31;
       int result = 1;
       result = prime * result + ((statement == null) ? 0 : statement.hashCode());
+      result = prime * result + ((null == rpcMetadata) ? 0 : rpcMetadata.hashCode());
       return result;
     }
 
@@ -1480,6 +1547,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != other.rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return true;
       }
 
@@ -1592,18 +1667,22 @@ public interface Service {
     public final Meta.Frame frame;
     public boolean missingStatement = false;
     public boolean missingResults = false;
+    public final RpcMetadataResponse rpcMetadata;
 
     FetchResponse() {
       frame = null;
+      rpcMetadata = null;
     }
 
     @JsonCreator
     public FetchResponse(@JsonProperty("frame") Meta.Frame frame,
         @JsonProperty("missingStatement") boolean missingStatement,
-        @JsonProperty("missingResults") boolean missingResults) {
+        @JsonProperty("missingResults") boolean missingResults,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.frame = frame;
       this.missingStatement = missingStatement;
       this.missingResults = missingResults;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override FetchResponse deserialize(Message genericMsg) {
@@ -1613,9 +1692,15 @@ public interface Service {
       }
 
       Responses.FetchResponse msg = (Responses.FetchResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc, Responses.FetchResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
 
       return new FetchResponse(Meta.Frame.fromProto(msg.getFrame()), msg.getMissingStatement(),
-          msg.getMissingResults());
+          msg.getMissingResults(), metadata);
     }
 
     @Override Responses.FetchResponse serialize() {
@@ -1625,6 +1710,10 @@ public interface Service {
         builder.setFrame(frame.toProto());
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.setMissingStatement(missingStatement)
           .setMissingResults(missingResults).build();
     }
@@ -1633,6 +1722,7 @@ public interface Service {
       final int prime = 31;
       int result = 1;
       result = prime * result + ((frame == null) ? 0 : frame.hashCode());
+      result = prime * result + ((null == rpcMetadata) ? 0 : rpcMetadata.hashCode());
       return result;
     }
 
@@ -1651,6 +1741,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != other.rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return missingStatement == other.missingStatement;
       }
 
@@ -1740,18 +1838,22 @@ public interface Service {
   class CreateStatementResponse extends Response {
     public final String connectionId;
     public final int statementId;
+    public final RpcMetadataResponse rpcMetadata;
 
     CreateStatementResponse() {
       connectionId = null;
       statementId = 0;
+      rpcMetadata = null;
     }
 
     @JsonCreator
     public CreateStatementResponse(
         @JsonProperty("connectionId") String connectionId,
-        @JsonProperty("statementId") int statementId) {
+        @JsonProperty("statementId") int statementId,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.connectionId = connectionId;
       this.statementId = statementId;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override CreateStatementResponse deserialize(Message genericMsg) {
@@ -1769,7 +1871,13 @@ public interface Service {
         connectionId = msg.getConnectionId();
       }
 
-      return new CreateStatementResponse(connectionId, msg.getStatementId());
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.CreateStatementResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new CreateStatementResponse(connectionId, msg.getStatementId(), metadata);
     }
 
     @Override Responses.CreateStatementResponse serialize() {
@@ -1780,6 +1888,10 @@ public interface Service {
         builder.setConnectionId(connectionId);
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       builder.setStatementId(statementId);
 
       return builder.build();
@@ -1790,6 +1902,7 @@ public interface Service {
       int result = 1;
       result = prime * result + ((connectionId == null) ? 0 : connectionId.hashCode());
       result = prime * result + statementId;
+      result = prime * result + ((null == rpcMetadata) ? 0 : rpcMetadata.hashCode());
       return result;
     }
 
@@ -1808,6 +1921,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != other.rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return statementId == other.statementId;
       }
 
@@ -1899,8 +2020,16 @@ public interface Service {
   /** Response from
    * {@link org.apache.calcite.avatica.remote.Service.CloseStatementRequest}. */
   class CloseStatementResponse extends Response {
+    public final RpcMetadataResponse rpcMetadata;
+
+    public CloseStatementResponse() {
+      rpcMetadata = null;
+    }
+
     @JsonCreator
-    public CloseStatementResponse() {}
+    public CloseStatementResponse(@JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
+      this.rpcMetadata = rpcMetadata;
+    }
 
     @Override CloseStatementResponse deserialize(Message genericMsg) {
       if (!(genericMsg instanceof Responses.CloseStatementResponse)) {
@@ -1908,22 +2037,52 @@ public interface Service {
             "Expected CloseStatementResponse, but got " + genericMsg.getClass().getName());
       }
 
-      return new CloseStatementResponse();
+      Responses.CloseStatementResponse msg = (Responses.CloseStatementResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.CloseStatementResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new CloseStatementResponse(metadata);
     }
 
     @Override Responses.CloseStatementResponse serialize() {
-      return Responses.CloseStatementResponse.newBuilder().build();
+      Responses.CloseStatementResponse.Builder builder =
+          Responses.CloseStatementResponse.newBuilder();
+
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
+      return builder.build();
     }
 
     @Override public int hashCode() {
-      return 0;
+      return (null == rpcMetadata) ? 0 : rpcMetadata.hashCode();
     }
 
     @Override public boolean equals(Object o) {
       if (o == this) {
         return true;
       }
-      return o instanceof CloseStatementResponse;
+      if (o == null || !(o instanceof CloseStatementResponse)) {
+        return false;
+      }
+
+      CloseStatementResponse other = (CloseStatementResponse) o;
+
+      if (null == rpcMetadata) {
+        if (null != other.rpcMetadata) {
+          return false;
+        }
+      } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+        return false;
+      }
+
+      return true;
     }
   }
 
@@ -2050,9 +2209,15 @@ public interface Service {
   /** Response from
    * {@link org.apache.calcite.avatica.remote.Service.OpenConnectionRequest}. */
   class OpenConnectionResponse extends Response {
+    public final RpcMetadataResponse rpcMetadata;
 
-    @JsonCreator
     public OpenConnectionResponse() {
+      rpcMetadata = null;
+    }
+
+    @JsonCreator
+    public OpenConnectionResponse(@JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override OpenConnectionResponse deserialize(Message genericMsg) {
@@ -2061,22 +2226,50 @@ public interface Service {
             "Expected OpenConnectionResponse, but got " + genericMsg.getClass().getName());
       }
 
-      return new OpenConnectionResponse();
+      Responses.OpenConnectionResponse msg = (Responses.OpenConnectionResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.OpenConnectionResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new OpenConnectionResponse(metadata);
     }
 
     @Override Responses.OpenConnectionResponse serialize() {
-      return Responses.OpenConnectionResponse.newBuilder().build();
+      Responses.OpenConnectionResponse.Builder builder =
+          Responses.OpenConnectionResponse.newBuilder();
+
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
+      return builder.build();
     }
 
     @Override public int hashCode() {
-      return 0;
+      return (null == rpcMetadata) ? 0 : rpcMetadata.hashCode();
     }
 
     @Override public boolean equals(Object o) {
       if (o == this) {
         return true;
       }
-      return o instanceof OpenConnectionResponse;
+      if (null == o || !(o instanceof OpenConnectionResponse)) {
+        return false;
+      }
+
+      OpenConnectionResponse other = (OpenConnectionResponse) o;
+      if (null == rpcMetadata) {
+        if (null != rpcMetadata) {
+          return false;
+        }
+      } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+        return false;
+      }
+      return true;
     }
   }
 
@@ -2160,9 +2353,16 @@ public interface Service {
   /** Response from
    * {@link org.apache.calcite.avatica.remote.Service.CloseConnectionRequest}. */
   class CloseConnectionResponse extends Response {
+    public final RpcMetadataResponse rpcMetadata;
+
+    public CloseConnectionResponse() {
+      rpcMetadata = null;
+    }
 
     @JsonCreator
-    public CloseConnectionResponse() {}
+    public CloseConnectionResponse(@JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
+      this.rpcMetadata = rpcMetadata;
+    }
 
     @Override CloseConnectionResponse deserialize(Message genericMsg) {
       if (!(genericMsg instanceof Responses.CloseConnectionResponse)) {
@@ -2170,22 +2370,51 @@ public interface Service {
             "Expected CloseConnectionResponse, but got " + genericMsg.getClass().getName());
       }
 
-      return new CloseConnectionResponse();
+      Responses.CloseConnectionResponse msg = (Responses.CloseConnectionResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.CloseConnectionResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new CloseConnectionResponse(metadata);
     }
 
     @Override Responses.CloseConnectionResponse serialize() {
-      return Responses.CloseConnectionResponse.newBuilder().build();
+      Responses.CloseConnectionResponse.Builder builder =
+          Responses.CloseConnectionResponse.newBuilder();
+
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
+      return builder.build();
     }
 
     @Override public int hashCode() {
-      return 0;
+      return (null == rpcMetadata) ? 0 : rpcMetadata.hashCode();
     }
 
     @Override public boolean equals(Object o) {
       if (o == this) {
         return true;
       }
-      return o instanceof CloseConnectionResponse;
+      if (o == null || !(o instanceof CloseConnectionResponse)) {
+        return false;
+      }
+      CloseConnectionResponse other = (CloseConnectionResponse) o;
+
+      if (null == rpcMetadata) {
+        if (null != other.rpcMetadata) {
+          return false;
+        }
+      } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+        return false;
+      }
+
+      return true;
     }
   }
 
@@ -2291,14 +2520,18 @@ public interface Service {
    * {@link Meta#connectionSync(Meta.ConnectionHandle, Meta.ConnectionProperties)}. */
   class ConnectionSyncResponse extends Response {
     public final Meta.ConnectionProperties connProps;
+    public final RpcMetadataResponse rpcMetadata;
 
     ConnectionSyncResponse() {
       connProps = null;
+      rpcMetadata = null;
     }
 
     @JsonCreator
-    public ConnectionSyncResponse(@JsonProperty("connProps") Meta.ConnectionProperties connProps) {
+    public ConnectionSyncResponse(@JsonProperty("connProps") Meta.ConnectionProperties connProps,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.connProps = connProps;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override ConnectionSyncResponse deserialize(Message genericMsg) {
@@ -2308,8 +2541,16 @@ public interface Service {
       }
 
       Responses.ConnectionSyncResponse msg = (Responses.ConnectionSyncResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
 
-      return new ConnectionSyncResponse(ConnectionPropertiesImpl.fromProto(msg.getConnProps()));
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.ConnectionSyncResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new ConnectionSyncResponse(ConnectionPropertiesImpl.fromProto(msg.getConnProps()),
+          metadata);
     }
 
     @Override Responses.ConnectionSyncResponse serialize() {
@@ -2320,15 +2561,19 @@ public interface Service {
         builder.setConnProps(connProps.toProto());
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.build();
     }
 
     @Override public int hashCode() {
-      if (null == connProps) {
-        return 0;
-      }
-
-      return connProps.hashCode();
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((connProps == null) ? 0 : connProps.hashCode());
+      result = prime * result + ((rpcMetadata == null) ? 0 : rpcMetadata.hashCode());
+      return result;
     }
 
     @Override public boolean equals(Object o) {
@@ -2346,6 +2591,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != other.rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return true;
       }
 
@@ -2357,14 +2610,18 @@ public interface Service {
    * {@link Meta#getDatabaseProperties(Meta.ConnectionHandle)}. */
   class DatabasePropertyResponse extends Response {
     public final Map<Meta.DatabaseProperty, Object> map;
+    public final RpcMetadataResponse rpcMetadata;
 
     DatabasePropertyResponse() {
       map = null;
+      rpcMetadata = null;
     }
 
     @JsonCreator
-    public DatabasePropertyResponse(@JsonProperty("map") Map<Meta.DatabaseProperty, Object> map) {
+    public DatabasePropertyResponse(@JsonProperty("map") Map<Meta.DatabaseProperty, Object> map,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.map = map;
+      this.rpcMetadata = rpcMetadata;
     }
 
     @Override DatabasePropertyResponse deserialize(Message genericMsg) {
@@ -2374,6 +2631,7 @@ public interface Service {
       }
 
       Responses.DatabasePropertyResponse msg = (Responses.DatabasePropertyResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
 
       HashMap<Meta.DatabaseProperty, Object> properties = new HashMap<>();
       for (Responses.DatabasePropertyElement property : msg.getPropsList()) {
@@ -2410,7 +2668,13 @@ public interface Service {
         properties.put(dbProp, obj);
       }
 
-      return new DatabasePropertyResponse(properties);
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.DatabasePropertyResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
+      return new DatabasePropertyResponse(properties, metadata);
     }
 
     @Override Responses.DatabasePropertyResponse serialize() {
@@ -2453,15 +2717,19 @@ public interface Service {
         }
       }
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.build();
     }
 
     @Override public int hashCode() {
-      if (null == map) {
-        return 0;
-      }
-
-      return map.hashCode();
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((map == null) ? 0 : map.hashCode());
+      result = prime * result + ((rpcMetadata == null) ? 0 : rpcMetadata.hashCode());
+      return result;
     }
 
     @Override public boolean equals(Object o) {
@@ -2479,6 +2747,14 @@ public interface Service {
           return false;
         }
 
+        if (null == rpcMetadata) {
+          if (null != other.rpcMetadata) {
+            return false;
+          }
+        } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+          return false;
+        }
+
         return true;
       }
 
@@ -2489,7 +2765,7 @@ public interface Service {
   /**
    * Response for any request that the server failed to successfully perform.
    * It is used internally by the transport layers to format errors for
-   * transport over the wire. Thus, {@link Request#apply} will never return
+   * transport over the wire. Thus, {@link Service#apply} will never return
    * an ErrorResponse.
    */
   public class ErrorResponse extends Response {
@@ -2503,6 +2779,7 @@ public interface Service {
     public final int errorCode;
     public final String sqlState;
     public final AvaticaSeverity severity;
+    public final RpcMetadataResponse rpcMetadata;
 
     ErrorResponse() {
       exceptions = Collections.singletonList("Unhandled exception");
@@ -2510,6 +2787,7 @@ public interface Service {
       errorCode = -1;
       sqlState = UNKNOWN_SQL_STATE;
       severity = AvaticaSeverity.UNKNOWN;
+      rpcMetadata = null;
     }
 
     @JsonCreator
@@ -2517,26 +2795,29 @@ public interface Service {
         @JsonProperty("errorMessage") String errorMessage,
         @JsonProperty("errorCode") int errorCode,
         @JsonProperty("sqlState") String sqlState,
-        @JsonProperty("severity") AvaticaSeverity severity) {
+        @JsonProperty("severity") AvaticaSeverity severity,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.exceptions = exceptions;
       this.errorMessage = errorMessage;
       this.errorCode = errorCode;
       this.sqlState = sqlState;
       this.severity = severity;
+      this.rpcMetadata = rpcMetadata;
     }
 
     protected ErrorResponse(Exception e, String errorMessage, int code, String sqlState,
-        AvaticaSeverity severity) {
-      this(errorMessage, code, sqlState, severity, toStackTraces(e));
+        AvaticaSeverity severity, RpcMetadataResponse rpcMetadata) {
+      this(errorMessage, code, sqlState, severity, toStackTraces(e), rpcMetadata);
     }
 
     protected ErrorResponse(String errorMessage, int code, String sqlState,
-        AvaticaSeverity severity, List<String> exceptions) {
+        AvaticaSeverity severity, List<String> exceptions, RpcMetadataResponse rpcMetadata) {
       this.exceptions = exceptions;
       this.errorMessage = errorMessage;
       this.errorCode = code;
       this.sqlState = sqlState;
       this.severity = severity;
+      this.rpcMetadata = rpcMetadata;
     }
 
     static List<String> toStackTraces(Exception e) {
@@ -2565,12 +2846,25 @@ public interface Service {
       }
 
       Responses.ErrorResponse msg = (Responses.ErrorResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc, Responses.ErrorResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
+
       return new ErrorResponse(msg.getExceptionsList(), msg.getErrorMessage(),
-          msg.getErrorCode(), msg.getSqlState(), AvaticaSeverity.fromProto(msg.getSeverity()));
+          msg.getErrorCode(), msg.getSqlState(), AvaticaSeverity.fromProto(msg.getSeverity()),
+          metadata);
     }
 
     @Override Responses.ErrorResponse serialize() {
       Responses.ErrorResponse.Builder builder = Responses.ErrorResponse.newBuilder();
+
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.addAllExceptions(exceptions).setErrorMessage(errorMessage)
           .setErrorCode(errorCode).setSqlState(sqlState).setSeverity(severity.toProto()).build();
     }
@@ -2582,6 +2876,7 @@ public interface Service {
       result = prime * result + errorCode;
       result = prime * result + ((sqlState == null) ? 0 : sqlState.hashCode());
       result = prime * result + ((severity == null) ? 0 : severity.hashCode());
+      result = prime * result + ((rpcMetadata == null) ? 0 : rpcMetadata.hashCode());
       return result;
     }
 
@@ -2626,12 +2921,20 @@ public interface Service {
         return false;
       }
 
+      if (null == rpcMetadata) {
+        if (null != other.rpcMetadata) {
+          return false;
+        }
+      } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+        return false;
+      }
+
       return true;
     }
 
     public AvaticaClientRuntimeException toException() {
       return new AvaticaClientRuntimeException("Remote driver error: " + errorMessage, errorCode,
-          sqlState, severity, exceptions);
+          sqlState, severity, exceptions, rpcMetadata);
     }
   }
 
@@ -2748,15 +3051,19 @@ public interface Service {
   class SyncResultsResponse extends Response {
     public boolean missingStatement = false;
     public final boolean moreResults;
+    public final RpcMetadataResponse rpcMetadata;
 
     SyncResultsResponse() {
       this.moreResults = false;
+      this.rpcMetadata = null;
     }
 
     public SyncResultsResponse(@JsonProperty("moreResults") boolean moreResults,
-        @JsonProperty("missingStatement") boolean missingStatement) {
+        @JsonProperty("missingStatement") boolean missingStatement,
+        @JsonProperty("rpcMetadata") RpcMetadataResponse rpcMetadata) {
       this.moreResults = moreResults;
       this.missingStatement = missingStatement;
+      this.rpcMetadata = rpcMetadata;
     }
 
     SyncResultsResponse deserialize(Message genericMsg) {
@@ -2766,13 +3073,24 @@ public interface Service {
       }
 
       Responses.SyncResultsResponse msg = (Responses.SyncResultsResponse) genericMsg;
+      Descriptor desc = msg.getDescriptorForType();
+
+      RpcMetadataResponse metadata = null;
+      if (ProtobufService.hasField(msg, desc,
+          Responses.SyncResultsResponse.METADATA_FIELD_NUMBER)) {
+        metadata = RpcMetadataResponse.fromProto(msg.getMetadata());
+      }
 
-      return new SyncResultsResponse(msg.getMoreResults(), msg.getMissingStatement());
+      return new SyncResultsResponse(msg.getMoreResults(), msg.getMissingStatement(), metadata);
     }
 
     Responses.SyncResultsResponse serialize() {
       Responses.SyncResultsResponse.Builder builder = Responses.SyncResultsResponse.newBuilder();
 
+      if (null != rpcMetadata) {
+        builder.setMetadata(rpcMetadata.serialize());
+      }
+
       return builder.setMoreResults(moreResults).setMissingStatement(missingStatement).build();
     }
 
@@ -2781,6 +3099,7 @@ public interface Service {
       int result = 1;
       result = prime * result + (missingStatement ? 1231 : 1237);
       result = prime * result + (moreResults ? 1231 : 1237);
+      result = prime * result + ((rpcMetadata == null) ? 0 : rpcMetadata.hashCode());
       return result;
     }
 
@@ -2794,9 +3113,88 @@ public interface Service {
 
       SyncResultsResponse other = (SyncResultsResponse) obj;
 
+      if (null == rpcMetadata) {
+        if (null != other.rpcMetadata) {
+          return false;
+        }
+      } else if (!rpcMetadata.equals(other.rpcMetadata)) {
+        return false;
+      }
+
       return missingStatement == other.missingStatement && moreResults == other.moreResults;
     }
   }
+
+  /**
+   * Response that includes information about the server that handled an RPC.
+   *
+   * This isn't really a "response", but we want to be able to be able to convert it to protobuf
+   * and back again, so ignore that there isn't an explicit endpoint for it.
+   */
+  public class RpcMetadataResponse extends Response {
+    public final String serverAddress;
+
+    public RpcMetadataResponse() {
+      this.serverAddress = null;
+    }
+
+    public RpcMetadataResponse(@JsonProperty("serverAddress") String serverAddress) {
+      this.serverAddress = serverAddress;
+    }
+
+    @Override
+    RpcMetadataResponse deserialize(Message genericMsg) {
+      if (!(genericMsg instanceof Responses.RpcMetadata)) {
+        throw new IllegalArgumentException("Expected RpcMetadata, but got "
+            + genericMsg.getClass().getName());
+      }
+
+      return fromProto((Responses.RpcMetadata) genericMsg);
+    }
+
+    @Override
+    Responses.RpcMetadata serialize() {
+      return Responses.RpcMetadata.newBuilder().setServerAddress(serverAddress).build();
+    }
+
+    static RpcMetadataResponse fromProto(Responses.RpcMetadata msg) {
+      Descriptor desc = msg.getDescriptorForType();
+
+      String serverAddress = null;
+      if (ProtobufService.hasField(msg, desc, Responses.RpcMetadata.SERVER_ADDRESS_FIELD_NUMBER)) {
+        serverAddress = msg.getServerAddress();
+      }
+
+      return new RpcMetadataResponse(serverAddress);
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((serverAddress == null) ? 0 : serverAddress.hashCode());
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj) {
+        return true;
+      }
+
+      if (obj == null || !(obj instanceof RpcMetadataResponse)) {
+        return false;
+      }
+
+      RpcMetadataResponse other = (RpcMetadataResponse) obj;
+      if (serverAddress == null) {
+        if (other.serverAddress != null) {
+          return false;
+        }
+      }
+      return serverAddress.equals(other.serverAddress);
+    }
+  }
 }
 
 // End Service.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/protobuf/responses.proto
----------------------------------------------------------------------
diff --git a/avatica/src/main/protobuf/responses.proto b/avatica/src/main/protobuf/responses.proto
index a899513..98ccf7f 100644
--- a/avatica/src/main/protobuf/responses.proto
+++ b/avatica/src/main/protobuf/responses.proto
@@ -29,17 +29,20 @@ message ResultSetResponse {
   Frame first_frame = 5;
   uint64 update_count = 6; // -1 for normal result sets, else this response contains a dummy result set
                                     // with no signature nor other data.
+  RpcMetadata metadata = 7;
 }
 
 // Response to PrepareAndExecuteRequest
 message ExecuteResponse {
   repeated ResultSetResponse results = 1;
   bool missing_statement = 2; // Did the request fail because of no-cached statement
+  RpcMetadata metadata = 3;
 }
 
 // Response to PrepareRequest
 message PrepareResponse {
   StatementHandle statement = 1;
+  RpcMetadata metadata = 2;
 }
 
 // Response to FetchRequest
@@ -47,42 +50,47 @@ message FetchResponse {
   Frame frame = 1;
   bool missing_statement = 2; // Did the request fail because of no-cached statement
   bool missing_results = 3; // Did the request fail because of a cached-statement w/o ResultSet
+  RpcMetadata metadata = 4;
 }
 
 // Response to CreateStatementRequest
 message CreateStatementResponse {
   string connection_id = 1;
   uint32 statement_id = 2;
+  RpcMetadata metadata = 3;
 }
 
 // Response to CloseStatementRequest
 message CloseStatementResponse {
-
+  RpcMetadata metadata = 1;
 }
 
 // Response to OpenConnectionRequest {
 message OpenConnectionResponse {
-
+  RpcMetadata metadata = 1;
 }
 
 // Response to CloseConnectionRequest {
 message CloseConnectionResponse {
-
+  RpcMetadata metadata = 1;
 }
 
 // Response to ConnectionSyncRequest
 message ConnectionSyncResponse {
   ConnectionProperties conn_props = 1;
+  RpcMetadata metadata = 2;
 }
 
 message DatabasePropertyElement {
   DatabaseProperty key = 1;
   TypedValue value = 2;
+  RpcMetadata metadata = 3;
 }
 
 // Response for Meta#getDatabaseProperties()
 message DatabasePropertyResponse {
   repeated DatabasePropertyElement props = 1;
+  RpcMetadata metadata = 2;
 }
 
 // Send contextual information about some error over the wire from the server.
@@ -92,9 +100,16 @@ message ErrorResponse {
   Severity severity = 3;
   uint32 error_code = 4; // numeric identifier for error
   string sql_state = 5; // five-character standard-defined value
+  RpcMetadata metadata = 6;
 }
 
 message SyncResultsResponse {
   bool missing_statement = 1; // Server doesn't have the statement with the ID from the request
   bool more_results = 2; // Should the client fetch() to get more results
+  RpcMetadata metadata = 3;
 }
+
+// Generic metadata for the server to return with each response.
+message RpcMetadata {
+  string server_address = 1; // The host:port of the server
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/test/java/org/apache/calcite/avatica/remote/ErrorResponseTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/remote/ErrorResponseTest.java b/avatica/src/test/java/org/apache/calcite/avatica/remote/ErrorResponseTest.java
index 7ee6fcf..f66cb26 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/remote/ErrorResponseTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/remote/ErrorResponseTest.java
@@ -19,6 +19,7 @@ package org.apache.calcite.avatica.remote;
 import org.apache.calcite.avatica.AvaticaClientRuntimeException;
 import org.apache.calcite.avatica.AvaticaSeverity;
 import org.apache.calcite.avatica.remote.Service.ErrorResponse;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import org.junit.Test;
 
@@ -39,8 +40,9 @@ public class ErrorResponseTest {
     final String state = "a1b2c";
     final AvaticaSeverity severity = AvaticaSeverity.ERROR;
     final List<String> exceptions = Arrays.asList("Server Stacktrace 1", "Server Stacktace 2");
-    assertEquals(new ErrorResponse(message, code, state, severity, exceptions),
-        new ErrorResponse(message, code, state, severity, exceptions));
+    final RpcMetadataResponse metadata = new RpcMetadataResponse("localhost:8765");
+    assertEquals(new ErrorResponse(message, code, state, severity, exceptions, metadata),
+        new ErrorResponse(message, code, state, severity, exceptions, metadata));
   }
 
   @Test public void testToClientRTE() {
@@ -49,7 +51,9 @@ public class ErrorResponseTest {
     final String state = "a1b2c";
     final AvaticaSeverity severity = AvaticaSeverity.ERROR;
     final List<String> exceptions = Arrays.asList("Server Stacktrace 1", "Server Stacktace 2");
-    final ErrorResponse resp = new ErrorResponse(message, code, state, severity, exceptions);
+    final RpcMetadataResponse metadata = new RpcMetadataResponse("localhost:8765");
+    final ErrorResponse resp = new ErrorResponse(message, code, state, severity, exceptions,
+        metadata);
     AvaticaClientRuntimeException exception = resp.toException();
     assertTrue("Expected error message to end with '" + resp.errorMessage + "', but was '"
         + exception.getMessage() + "'", exception.getMessage().endsWith(resp.errorMessage));
@@ -57,6 +61,7 @@ public class ErrorResponseTest {
     assertEquals(resp.severity, exception.getSeverity());
     assertEquals(resp.sqlState, exception.getSqlState());
     assertEquals(resp.exceptions, exception.getServerExceptions());
+    assertEquals(resp.rpcMetadata, exception.getRpcMetadata());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
index 3c25e13..7d24598 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
@@ -24,6 +24,7 @@ import org.apache.calcite.avatica.proto.Responses;
 import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
 import org.apache.calcite.avatica.remote.Service.FetchRequest;
 import org.apache.calcite.avatica.remote.Service.FetchResponse;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -84,7 +85,8 @@ public class ProtobufHandlerTest {
     frameRows.add(new Object[] {true, "my_string"});
 
     Meta.Frame frame = Frame.create(0, true, frameRows);
-    FetchResponse response = new FetchResponse(frame, false, false);
+    RpcMetadataResponse metadata = new RpcMetadataResponse("localhost:8765");
+    FetchResponse response = new FetchResponse(frame, false, false, metadata);
 
     when(translation.parseRequest(serializedRequest)).thenReturn(request);
     when(service.apply(request)).thenReturn(response);

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
index 3ca44e9..8e0d738 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
@@ -51,6 +51,7 @@ import org.apache.calcite.avatica.remote.Service.PrepareResponse;
 import org.apache.calcite.avatica.remote.Service.Request;
 import org.apache.calcite.avatica.remote.Service.Response;
 import org.apache.calcite.avatica.remote.Service.ResultSetResponse;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 import org.apache.calcite.avatica.remote.Service.SchemasRequest;
 import org.apache.calcite.avatica.remote.Service.SyncResultsRequest;
 import org.apache.calcite.avatica.remote.Service.SyncResultsResponse;
@@ -248,6 +249,7 @@ public class ProtobufTranslationImplTest<T> {
    * Generates a collection of Responses whose serialization will be tested.
    */
   private static List<Response> getResponses() {
+    final RpcMetadataResponse rpcMetadata = new RpcMetadataResponse("localhost:8765");
     LinkedList<Response> responses = new LinkedList<>();
 
     // Nested classes (Signature, ColumnMetaData, CursorFactory, etc) are implicitly getting tested)
@@ -273,48 +275,49 @@ public class ProtobufTranslationImplTest<T> {
 
     // And then create a ResultSetResponse
     ResultSetResponse results1 = new ResultSetResponse("connectionId", Integer.MAX_VALUE, true,
-        signature, frame, Long.MAX_VALUE);
+        signature, frame, Long.MAX_VALUE, rpcMetadata);
     responses.add(results1);
 
-    responses.add(new CloseStatementResponse());
+    responses.add(new CloseStatementResponse(rpcMetadata));
 
     ConnectionPropertiesImpl connProps = new ConnectionPropertiesImpl(false, true,
         Integer.MAX_VALUE, "catalog", "schema");
-    responses.add(new ConnectionSyncResponse(connProps));
+    responses.add(new ConnectionSyncResponse(connProps, rpcMetadata));
 
-    responses.add(new OpenConnectionResponse());
-    responses.add(new CloseConnectionResponse());
+    responses.add(new OpenConnectionResponse(rpcMetadata));
+    responses.add(new CloseConnectionResponse(rpcMetadata));
 
-    responses.add(new CreateStatementResponse("connectionId", Integer.MAX_VALUE));
+    responses.add(new CreateStatementResponse("connectionId", Integer.MAX_VALUE, rpcMetadata));
 
     Map<Meta.DatabaseProperty, Object> propertyMap = new HashMap<>();
     for (Meta.DatabaseProperty prop : Meta.DatabaseProperty.values()) {
       propertyMap.put(prop, prop.defaultValue);
     }
-    responses.add(new DatabasePropertyResponse(propertyMap));
+    responses.add(new DatabasePropertyResponse(propertyMap, rpcMetadata));
 
-    responses.add(new ExecuteResponse(Arrays.asList(results1, results1, results1), false));
-    responses.add(new FetchResponse(frame, false, false));
-    responses.add(new FetchResponse(frame, true, true));
-    responses.add(new FetchResponse(frame, false, true));
+    responses.add(new ExecuteResponse(Arrays.asList(results1, results1, results1), false,
+        rpcMetadata));
+    responses.add(new FetchResponse(frame, false, false, rpcMetadata));
+    responses.add(new FetchResponse(frame, true, true, rpcMetadata));
+    responses.add(new FetchResponse(frame, false, true, rpcMetadata));
     responses.add(
         new PrepareResponse(
             new Meta.StatementHandle("connectionId", Integer.MAX_VALUE,
-                signature)));
+                signature), rpcMetadata));
 
     StringWriter sw = new StringWriter();
     new Exception().printStackTrace(new PrintWriter(sw));
     responses.add(
         new ErrorResponse(Collections.singletonList(sw.toString()), "Test Error Message",
             ErrorResponse.UNKNOWN_ERROR_CODE, ErrorResponse.UNKNOWN_SQL_STATE,
-            AvaticaSeverity.WARNING));
+            AvaticaSeverity.WARNING, rpcMetadata));
 
     // No more results, statement not missing
-    responses.add(new SyncResultsResponse(false, false));
+    responses.add(new SyncResultsResponse(false, false, rpcMetadata));
     // Missing statement, no results
-    responses.add(new SyncResultsResponse(false, true));
+    responses.add(new SyncResultsResponse(false, true, rpcMetadata));
     // More results, no missing statement
-    responses.add(new SyncResultsResponse(true, false));
+    responses.add(new SyncResultsResponse(true, false, rpcMetadata));
 
     return responses;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaClientRuntimeExceptionTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaClientRuntimeExceptionTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaClientRuntimeExceptionTest.java
index d457aa3..411f29c 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaClientRuntimeExceptionTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaClientRuntimeExceptionTest.java
@@ -18,6 +18,7 @@ package org.apache.calcite.avatica.test;
 
 import org.apache.calcite.avatica.AvaticaClientRuntimeException;
 import org.apache.calcite.avatica.AvaticaSeverity;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import org.junit.Test;
 
@@ -37,12 +38,14 @@ public class AvaticaClientRuntimeExceptionTest {
     final String sqlState = "abc12";
     final AvaticaSeverity severity = AvaticaSeverity.ERROR;
     final List<String> stacktraces = Arrays.asList("my stack trace");
+    final RpcMetadataResponse metadata = new RpcMetadataResponse("localhost:8765");
     AvaticaClientRuntimeException e = new AvaticaClientRuntimeException(errorMsg, errorCode,
-        sqlState, severity, stacktraces);
+        sqlState, severity, stacktraces, metadata);
     assertEquals(errorMsg, e.getMessage());
     assertEquals(errorCode, e.getErrorCode());
     assertEquals(severity, e.getSeverity());
     assertEquals(stacktraces, e.getServerExceptions());
+    assertEquals(metadata, e.getRpcMetadata());
   }
 
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaSqlExceptionTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaSqlExceptionTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaSqlExceptionTest.java
index fb10c45..3d7b5b0 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaSqlExceptionTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaSqlExceptionTest.java
@@ -35,13 +35,16 @@ public class AvaticaSqlExceptionTest {
     final int code = 42;
     final String sql = "SELECT foo FROM bar;";
     final String stacktrace = "My Stack Trace";
+    final String server = "localhost:8765";
 
-    AvaticaSqlException e = new AvaticaSqlException(msg, sql, code, Arrays.asList(stacktrace));
+    AvaticaSqlException e = new AvaticaSqlException(msg, sql, code, Arrays.asList(stacktrace),
+        server);
     assertTrue(e.getMessage().contains(msg));
     assertEquals(code, e.getErrorCode());
     assertEquals(sql, e.getSQLState());
     assertEquals(1, e.getStackTraces().size());
     assertEquals(stacktrace, e.getStackTraces().get(0));
+    assertEquals(server, e.getRemoteServer());
   }
 
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
index dccf889..bbfc4a7 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
@@ -118,6 +118,9 @@ public class JsonHandlerTest {
     @Override public ExecuteResponse apply(ExecuteRequest request) {
       return null;
     }
+
+    @Override
+    public void setRpcMetadata(RpcMetadataResponse metadata) {}
   }
 
   /**
@@ -146,10 +149,10 @@ public class JsonHandlerTest {
 
       final Service.ResultSetResponse resultSetResponse =
           new Service.ResultSetResponse(UUID.randomUUID().toString(),
-              RANDOM.nextInt(), false, signature, Meta.Frame.EMPTY, -1L);
+              RANDOM.nextInt(), false, signature, Meta.Frame.EMPTY, -1L, null);
 
       return new Service.ExecuteResponse(
-          Collections.singletonList(resultSetResponse), false);
+          Collections.singletonList(resultSetResponse), false, null);
     }
   }
 


[3/3] calcite git commit: [CALCITE-989] Add server's address in each response

Posted by el...@apache.org.
[CALCITE-989] Add server's address in each response

If the clients knows what server processed a response, the
client do perform their own load-balancing.

Fix some server Handler class hierarchy to make more sense
supporting both json and protobuf.


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/3be816f4
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/3be816f4
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/3be816f4

Branch: refs/heads/master
Commit: 3be816f450450e8e43286e6ea208af6e30520146
Parents: 81b4876
Author: Josh Elser <el...@apache.org>
Authored: Tue Nov 24 19:03:44 2015 -0500
Committer: Josh Elser <el...@apache.org>
Committed: Wed Dec 2 13:03:51 2015 -0500

----------------------------------------------------------------------
 .../calcite/avatica/server/AvaticaHandler.java  |   60 +-
 .../avatica/server/AvaticaJsonHandler.java      |   93 +
 .../avatica/server/AvaticaProtobufHandler.java  |   17 +-
 .../server/DelegatingAvaticaHandler.java        |  126 +
 .../calcite/avatica/server/HandlerFactory.java  |    2 +-
 .../calcite/avatica/server/HttpServer.java      |   47 +-
 .../org/apache/calcite/avatica/server/Main.java |    2 +-
 .../remote/AlternatingRemoteMetaTest.java       |    4 +-
 .../calcite/avatica/remote/RemoteMetaTest.java  |   68 +-
 .../avatica/server/HandlerFactoryTest.java      |    2 +-
 .../avatica/AvaticaClientRuntimeException.java  |   10 +-
 .../calcite/avatica/AvaticaSqlException.java    |   12 +-
 .../java/org/apache/calcite/avatica/Helper.java |    6 +-
 .../apache/calcite/avatica/proto/Responses.java | 3110 +++++++++++++++++-
 .../calcite/avatica/remote/AbstractHandler.java |    9 +-
 .../calcite/avatica/remote/AbstractService.java |   14 +-
 .../apache/calcite/avatica/remote/Handler.java  |    9 +
 .../calcite/avatica/remote/LocalService.java    |   44 +-
 .../avatica/remote/MockProtobufService.java     |   12 +-
 .../avatica/remote/ProtobufTranslationImpl.java |    4 +
 .../apache/calcite/avatica/remote/Service.java  |  506 ++-
 avatica/src/main/protobuf/responses.proto       |   21 +-
 .../avatica/remote/ErrorResponseTest.java       |   11 +-
 .../avatica/remote/ProtobufHandlerTest.java     |    4 +-
 .../remote/ProtobufTranslationImplTest.java     |   35 +-
 .../test/AvaticaClientRuntimeExceptionTest.java |    5 +-
 .../avatica/test/AvaticaSqlExceptionTest.java   |    5 +-
 .../calcite/avatica/test/JsonHandlerTest.java   |    7 +-
 28 files changed, 4001 insertions(+), 244 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
index f7c4800..d5501b9 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
@@ -16,65 +16,15 @@
  */
 package org.apache.calcite.avatica.server;
 
-import org.apache.calcite.avatica.AvaticaUtils;
-import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
-import org.apache.calcite.avatica.remote.JsonHandler;
-import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
-import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.ServletInputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.server.Handler;
 
 /**
- * Jetty handler that executes Avatica JSON request-responses.
+ * A custom interface that extends the Jetty interface to enable extra control within Avatica.
  */
-public class AvaticaHandler extends AbstractHandler {
-  private static final Log LOG = LogFactory.getLog(AvaticaHandler.class);
-
-  final JsonHandler jsonHandler;
+public interface AvaticaHandler extends Handler {
 
-  public AvaticaHandler(Service service) {
-    this.jsonHandler = new JsonHandler(service);
-  }
+  void setServerRpcMetadata(RpcMetadataResponse metadata);
 
-  public void handle(String target, Request baseRequest,
-      HttpServletRequest request, HttpServletResponse response)
-      throws IOException, ServletException {
-    response.setContentType("application/json;charset=utf-8");
-    response.setStatus(HttpServletResponse.SC_OK);
-    if (request.getMethod().equals("POST")) {
-      // First look for a request in the header, then look in the body.
-      // The latter allows very large requests without hitting HTTP 413.
-      String rawRequest = request.getHeader("request");
-      if (rawRequest == null) {
-        try (ServletInputStream inputStream = request.getInputStream()) {
-          rawRequest = AvaticaUtils.readFully(inputStream);
-        }
-      }
-      final String jsonRequest =
-          new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
-      if (LOG.isTraceEnabled()) {
-        LOG.trace("request: " + jsonRequest);
-      }
-
-      final HandlerResponse<String> jsonResponse = jsonHandler.apply(jsonRequest);
-      if (LOG.isTraceEnabled()) {
-        LOG.trace("response: " + jsonResponse);
-      }
-      baseRequest.setHandled(true);
-      // Set the status code and write out the response.
-      response.setStatus(jsonResponse.getStatusCode());
-      response.getWriter().println(jsonResponse.getResponse());
-    }
-  }
 }
-
-// End AvaticaHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
new file mode 100644
index 0000000..106d53d
--- /dev/null
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica.server;
+
+import org.apache.calcite.avatica.AvaticaUtils;
+import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
+import org.apache.calcite.avatica.remote.JsonHandler;
+import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Jetty handler that executes Avatica JSON request-responses.
+ */
+public class AvaticaJsonHandler extends AbstractHandler implements AvaticaHandler {
+  private static final Log LOG = LogFactory.getLog(AvaticaJsonHandler.class);
+
+  final Service service;
+  final JsonHandler jsonHandler;
+
+  public AvaticaJsonHandler(Service service) {
+    this.service = Objects.requireNonNull(service);
+    this.jsonHandler = new JsonHandler(service);
+  }
+
+  public void handle(String target, Request baseRequest,
+      HttpServletRequest request, HttpServletResponse response)
+      throws IOException, ServletException {
+    response.setContentType("application/json;charset=utf-8");
+    response.setStatus(HttpServletResponse.SC_OK);
+    if (request.getMethod().equals("POST")) {
+      // First look for a request in the header, then look in the body.
+      // The latter allows very large requests without hitting HTTP 413.
+      String rawRequest = request.getHeader("request");
+      if (rawRequest == null) {
+        try (ServletInputStream inputStream = request.getInputStream()) {
+          rawRequest = AvaticaUtils.readFully(inputStream);
+        }
+      }
+      final String jsonRequest =
+          new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
+      if (LOG.isTraceEnabled()) {
+        LOG.trace("request: " + jsonRequest);
+      }
+
+      final HandlerResponse<String> jsonResponse = jsonHandler.apply(jsonRequest);
+      if (LOG.isTraceEnabled()) {
+        LOG.trace("response: " + jsonResponse);
+      }
+      baseRequest.setHandled(true);
+      // Set the status code and write out the response.
+      response.setStatus(jsonResponse.getStatusCode());
+      response.getWriter().println(jsonResponse.getResponse());
+    }
+  }
+
+  @Override
+  public void setServerRpcMetadata(RpcMetadataResponse metadata) {
+    // Set the metadata for the normal service calls
+    service.setRpcMetadata(metadata);
+    // Also add it to the handler to include with exceptions
+    jsonHandler.setRpcMetadata(metadata);
+  }
+}
+
+// End AvaticaHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
index 9dc6df0..bd4a8c9 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
@@ -22,6 +22,7 @@ import org.apache.calcite.avatica.remote.ProtobufHandler;
 import org.apache.calcite.avatica.remote.ProtobufTranslation;
 import org.apache.calcite.avatica.remote.ProtobufTranslationImpl;
 import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -30,6 +31,8 @@ import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 
 import java.io.IOException;
+import java.util.Objects;
+
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
@@ -38,14 +41,16 @@ import javax.servlet.http.HttpServletResponse;
 /**
  * Jetty handler that executes Avatica JSON request-responses.
  */
-public class AvaticaProtobufHandler extends AbstractHandler {
-  private static final Log LOG = LogFactory.getLog(AvaticaHandler.class);
+public class AvaticaProtobufHandler extends AbstractHandler implements AvaticaHandler {
+  private static final Log LOG = LogFactory.getLog(AvaticaJsonHandler.class);
 
+  private final Service service;
   private final ProtobufHandler pbHandler;
   private final ProtobufTranslation protobufTranslation;
 
   public AvaticaProtobufHandler(Service service) {
     this.protobufTranslation = new ProtobufTranslationImpl();
+    this.service = Objects.requireNonNull(service);
     this.pbHandler = new ProtobufHandler(service, protobufTranslation);
   }
 
@@ -67,6 +72,14 @@ public class AvaticaProtobufHandler extends AbstractHandler {
       response.getOutputStream().write(handlerResponse.getResponse());
     }
   }
+
+  @Override
+  public void setServerRpcMetadata(RpcMetadataResponse metadata) {
+    // Set the metadata for the normal service calls
+    service.setRpcMetadata(metadata);
+    // Also add it to the handler to include with exceptions
+    pbHandler.setRpcMetadata(metadata);
+  }
 }
 
 // End AvaticaProtobufHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
new file mode 100644
index 0000000..4b2457c
--- /dev/null
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica.server;
+
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * An AvaticaHandler implementation which delegates to a provided Jetty Handler instance.
+ *
+ * This implementation provides a no-op implementation for
+ * {@link #setServerRpcMetadata(RpcMetadataResponse)}.
+ */
+public class DelegatingAvaticaHandler implements AvaticaHandler {
+  private static final Log LOG = LogFactory.getLog(DelegatingAvaticaHandler.class);
+
+  private final Handler handler;
+
+  public DelegatingAvaticaHandler(Handler handler) {
+    this.handler = Objects.requireNonNull(handler);
+  }
+
+  @Override
+  public void handle(String target, Request baseRequest, HttpServletRequest request,
+      HttpServletResponse response) throws IOException, ServletException {
+    handler.handle(target, baseRequest, request, response);
+  }
+
+  @Override
+  public void setServer(Server server) {
+    handler.setServer(server);
+  }
+
+  @Override
+  public Server getServer() {
+    return handler.getServer();
+  }
+
+  @Override
+  public void destroy() {
+    handler.destroy();
+  }
+
+  @Override
+  public void start() throws Exception {
+    handler.start();
+  }
+
+  @Override
+  public void stop() throws Exception {
+    handler.stop();
+  }
+
+  @Override
+  public boolean isRunning() {
+    return handler.isRunning();
+  }
+
+  @Override
+  public boolean isStarted() {
+    return handler.isStarted();
+  }
+
+  @Override
+  public boolean isStarting() {
+    return handler.isStarting();
+  }
+
+  @Override
+  public boolean isStopping() {
+    return handler.isStopping();
+  }
+
+  @Override
+  public boolean isStopped() {
+    return handler.isStopped();
+  }
+
+  @Override
+  public boolean isFailed() {
+    return handler.isFailed();
+  }
+
+  @Override
+  public void addLifeCycleListener(Listener listener) {
+    handler.addLifeCycleListener(listener);
+  }
+
+  @Override
+  public void removeLifeCycleListener(Listener listener) {
+    handler.removeLifeCycleListener(listener);
+  }
+
+  @Override
+  public void setServerRpcMetadata(RpcMetadataResponse metadata) {
+    LOG.warn("Setting RpcMetadata is not implemented for DelegatingAvaticaHandler");
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
index c98f593..724626d 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
@@ -35,7 +35,7 @@ public class HandlerFactory {
   public Handler getHandler(Service service, Driver.Serialization serialization) {
     switch (serialization) {
     case JSON:
-      return new AvaticaHandler(service);
+      return new AvaticaJsonHandler(service);
     case PROTOBUF:
       return new AvaticaProtobufHandler(service);
     default:

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
index 161a752..cffbf60 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.avatica.server;
 
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -27,6 +29,9 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
 import org.eclipse.jetty.server.handler.HandlerList;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 /**
  * Avatica HTTP server.
  *
@@ -38,17 +43,35 @@ public class HttpServer {
 
   private Server server;
   private int port = -1;
-  private final Handler handler;
+  private final AvaticaHandler handler;
 
+  @Deprecated
   public HttpServer(Handler handler) {
+    this(wrapJettyHandler(handler));
+  }
+
+  public HttpServer(AvaticaHandler handler) {
     this(0, handler);
   }
 
+  @Deprecated
   public HttpServer(int port, Handler handler) {
+    this(port, wrapJettyHandler(handler));
+  }
+
+  public HttpServer(int port, AvaticaHandler handler) {
     this.port = port;
     this.handler = handler;
   }
 
+  private static AvaticaHandler wrapJettyHandler(Handler handler) {
+    if (handler instanceof AvaticaHandler) {
+      return (AvaticaHandler) handler;
+    }
+    // Backwards compatibility, noop's the AvaticaHandler interface
+    return new DelegatingAvaticaHandler(handler);
+  }
+
   public void start() {
     if (server != null) {
       throw new RuntimeException("Server is already started");
@@ -74,6 +97,28 @@ public class HttpServer {
     port = connector.getLocalPort();
 
     LOG.info("Service listening on port " + getPort() + ".");
+
+    // Set the information about the address for this server
+    try {
+      this.handler.setServerRpcMetadata(createRpcServerMetadata(connector));
+    } catch (UnknownHostException e) {
+      // Failed to do the DNS lookup, bail out.
+      throw new RuntimeException(e);
+    }
+  }
+
+  private RpcMetadataResponse createRpcServerMetadata(ServerConnector connector) throws
+      UnknownHostException {
+    String host = connector.getHost();
+    if (null == host) {
+      // "null" means binding to all interfaces, we need to pick one so the client gets a real
+      // address and not "0.0.0.0" or similar.
+      host = InetAddress.getLocalHost().getHostName();
+    }
+
+    final int port = connector.getLocalPort();
+
+    return new RpcMetadataResponse(String.format("%s:%d", host, port));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
index 82691f6..8b05931 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
@@ -46,7 +46,7 @@ public class Main {
 
   private static final HandlerFactory JSON_HANDLER_FACTORY = new HandlerFactory() {
     public AbstractHandler createHandler(Service service) {
-      return new AvaticaHandler(service);
+      return new AvaticaJsonHandler(service);
     }
   };
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
index df2862d..ffd6f7c 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
@@ -23,7 +23,7 @@ import org.apache.calcite.avatica.ConnectionPropertiesImpl;
 import org.apache.calcite.avatica.ConnectionSpec;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.jdbc.JdbcMeta;
-import org.apache.calcite.avatica.server.AvaticaHandler;
+import org.apache.calcite.avatica.server.AvaticaJsonHandler;
 import org.apache.calcite.avatica.server.HttpServer;
 import org.apache.calcite.avatica.server.Main;
 import org.apache.calcite.avatica.server.Main.HandlerFactory;
@@ -193,7 +193,7 @@ public class AlternatingRemoteMetaTest {
       }
       HttpServer jsonServer = Main.start(mainArgs, 0, new HandlerFactory() {
         @Override public AbstractHandler createHandler(Service service) {
-          return new AvaticaHandler(service);
+          return new AvaticaJsonHandler(service);
         }
       });
       ACTIVE_SERVERS.add(jsonServer);

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 6cb4508..fbc91e6 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -24,7 +24,8 @@ import org.apache.calcite.avatica.ConnectionSpec;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.jdbc.JdbcMeta;
 import org.apache.calcite.avatica.remote.Service.ErrorResponse;
-import org.apache.calcite.avatica.server.AvaticaHandler;
+import org.apache.calcite.avatica.remote.Service.Response;
+import org.apache.calcite.avatica.server.AvaticaJsonHandler;
 import org.apache.calcite.avatica.server.AvaticaProtobufHandler;
 import org.apache.calcite.avatica.server.HttpServer;
 import org.apache.calcite.avatica.server.Main;
@@ -34,8 +35,6 @@ import org.apache.calcite.avatica.util.ArrayImpl;
 import com.google.common.base.Throwables;
 import com.google.common.cache.Cache;
 
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
 import org.junit.AfterClass;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -45,6 +44,8 @@ import org.junit.runners.Parameterized.Parameters;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.sql.Array;
 import java.sql.Connection;
@@ -55,6 +56,7 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
@@ -66,6 +68,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -81,6 +84,8 @@ public class RemoteMetaTest {
 
   private final HttpServer server;
   private final String url;
+  private final int port;
+  private final Driver.Serialization serialization;
 
   @Parameters
   public static List<Object[]> parameters() throws Exception {
@@ -91,15 +96,15 @@ public class RemoteMetaTest {
     // Bind to '0' to pluck an ephemeral port instead of expecting a certain one to be free
 
     final HttpServer jsonServer = Main.start(mainArgs, 0, new HandlerFactory() {
-      @Override public AbstractHandler createHandler(Service service) {
-        return new AvaticaHandler(service);
+      @Override public AvaticaJsonHandler createHandler(Service service) {
+        return new AvaticaJsonHandler(service);
       }
     });
     params.add(new Object[] {jsonServer, Driver.Serialization.JSON});
     ACTIVE_SERVERS.add(jsonServer);
 
     final HttpServer protobufServer = Main.start(mainArgs, 0, new HandlerFactory() {
-      @Override public AbstractHandler createHandler(Service service) {
+      @Override public AvaticaProtobufHandler createHandler(Service service) {
         return new AvaticaProtobufHandler(service);
       }
     });
@@ -112,7 +117,8 @@ public class RemoteMetaTest {
 
   public RemoteMetaTest(HttpServer server, Driver.Serialization serialization) {
     this.server = server;
-    final int port = server.getPort();
+    this.port = this.server.getPort();
+    this.serialization = serialization;
     url = "jdbc:avatica:remote:url=http://localhost:" + port + ";serialization="
         + serialization.name();
   }
@@ -452,6 +458,54 @@ public class RemoteMetaTest {
     }
   }
 
+  @Test public void testServerAddressInResponse() throws Exception {
+    ConnectionSpec.getDatabaseLock().lock();
+    try {
+      URL url = new URL("http://localhost:" + this.port);
+      AvaticaHttpClient httpClient = new AvaticaHttpClientImpl(url);
+      byte[] request;
+
+      Service.OpenConnectionRequest jsonReq = new Service.OpenConnectionRequest(
+          UUID.randomUUID().toString(), Collections.<String, String>emptyMap());
+      switch (this.serialization) {
+      case JSON:
+        request = JsonService.MAPPER.writeValueAsBytes(jsonReq);
+        break;
+      case PROTOBUF:
+        ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
+        request = pbTranslation.serializeRequest(jsonReq);
+        break;
+      default:
+        throw new IllegalStateException("Should not reach here");
+      }
+
+      byte[] response = httpClient.send(request);
+      Service.OpenConnectionResponse openCnxnResp;
+      switch (this.serialization) {
+      case JSON:
+        openCnxnResp = JsonService.MAPPER.readValue(response,
+            Service.OpenConnectionResponse.class);
+        break;
+      case PROTOBUF:
+        ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
+        Response genericResp = pbTranslation.parseResponse(response);
+        assertTrue("Expected an OpenConnnectionResponse, but got " + genericResp.getClass(),
+            genericResp instanceof Service.OpenConnectionResponse);
+        openCnxnResp = (Service.OpenConnectionResponse) genericResp;
+        break;
+      default:
+        throw new IllegalStateException("Should not reach here");
+      }
+
+      String hostname = InetAddress.getLocalHost().getHostName();
+
+      assertNotNull(openCnxnResp.rpcMetadata);
+      assertEquals(hostname + ":" + this.port, openCnxnResp.rpcMetadata.serverAddress);
+    } finally {
+      ConnectionSpec.getDatabaseLock().unlock();
+    }
+  }
+
   /** Factory that provides a {@link JdbcMeta}. */
   public static class FullyRemoteJdbcMetaFactory implements Meta.Factory {
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
index 13e9f7d..3504e02 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
@@ -44,7 +44,7 @@ public class HandlerFactoryTest {
   public void testJson() {
     Handler handler = factory.getHandler(service, Serialization.JSON);
     assertTrue("Expected an implementation of the AvaticaHandler, "
-        + "but got " + handler.getClass(), handler instanceof AvaticaHandler);
+        + "but got " + handler.getClass(), handler instanceof AvaticaJsonHandler);
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
index 6859763..df03b03 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
@@ -18,6 +18,7 @@ package org.apache.calcite.avatica;
 
 import org.apache.calcite.avatica.remote.AvaticaRuntimeException;
 import org.apache.calcite.avatica.remote.Service.ErrorResponse;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
 
 import java.util.Collections;
 import java.util.List;
@@ -36,14 +37,16 @@ public class AvaticaClientRuntimeException extends RuntimeException {
   private final String sqlState;
   private final AvaticaSeverity severity;
   private final List<String> serverExceptions;
+  private final RpcMetadataResponse metadata;
 
   public AvaticaClientRuntimeException(String errorMessage, int errorCode, String sqlState,
-      AvaticaSeverity severity, List<String> serverExceptions) {
+      AvaticaSeverity severity, List<String> serverExceptions, RpcMetadataResponse metadata) {
     super(errorMessage);
     this.errorCode = errorCode;
     this.sqlState = sqlState;
     this.severity = severity;
     this.serverExceptions = serverExceptions;
+    this.metadata = metadata;
   }
 
   public AvaticaClientRuntimeException(String message, Throwable cause) {
@@ -52,6 +55,7 @@ public class AvaticaClientRuntimeException extends RuntimeException {
     sqlState = ErrorResponse.UNKNOWN_SQL_STATE;
     severity = AvaticaSeverity.UNKNOWN;
     serverExceptions = Collections.singletonList("");
+    metadata = null;
   }
 
   public int getErrorCode() {
@@ -70,6 +74,10 @@ public class AvaticaClientRuntimeException extends RuntimeException {
     return serverExceptions;
   }
 
+  public RpcMetadataResponse getRpcMetadata() {
+    return metadata;
+  }
+
   @Override public String toString() {
     StringBuilder sb = new StringBuilder(64);
     sb.append(getClass().getSimpleName()).append(": ")

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
index cfcf305..9408a7b 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
@@ -31,6 +31,7 @@ public class AvaticaSqlException extends SQLException {
 
   private final String errorMessage;
   private final List<String> stackTraces;
+  private final String remoteServer;
 
   /**
    * Construct the Exception with information from the server.
@@ -38,12 +39,14 @@ public class AvaticaSqlException extends SQLException {
    * @param errorMessage A human-readable error message.
    * @param errorCode An integer corresponding to a known error.
    * @param stackTraces Server-side stacktrace.
+   * @param remoteServer The host:port where the Avatica server is located
    */
   public AvaticaSqlException(String errorMessage, String sqlState, int errorCode,
-      List<String> stackTraces) {
+      List<String> stackTraces, String remoteServer) {
     super("Error " + errorCode + " (" + sqlState + ") : " + errorMessage, sqlState, errorCode);
     this.errorMessage = errorMessage;
     this.stackTraces = Objects.requireNonNull(stackTraces);
+    this.remoteServer = remoteServer;
   }
 
   public String getErrorMessage() {
@@ -57,6 +60,13 @@ public class AvaticaSqlException extends SQLException {
     return stackTraces;
   }
 
+  /**
+   * @return The host:port for the remote Avatica server. May be null.
+   */
+  public String getRemoteServer() {
+    return remoteServer;
+  }
+
   // printStackTrace() will get redirected to printStackTrace(PrintStream), don't need to override.
 
   @Override public void printStackTrace(PrintStream stream) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Helper.java b/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
index 54be099..27c6056 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
@@ -46,8 +46,12 @@ public class Helper {
       // The AvaticaClientRuntimeException contains extra information about what/why
       // the exception was thrown that we can pass back to the user.
       AvaticaClientRuntimeException rte = (AvaticaClientRuntimeException) e;
+      String serverAddress = null;
+      if (null != rte.getRpcMetadata()) {
+        serverAddress = rte.getRpcMetadata().serverAddress;
+      }
       return new AvaticaSqlException(message, rte.getSqlState(), rte.getErrorCode(),
-          rte.getServerExceptions());
+          rte.getServerExceptions(), serverAddress);
     }
     return new SQLException(message, e);
   }


[2/3] calcite git commit: [CALCITE-989] Add server's address in each response

Posted by el...@apache.org.
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/proto/Responses.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/proto/Responses.java b/avatica/src/main/java/org/apache/calcite/avatica/proto/Responses.java
index 9392326..f364021 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/proto/Responses.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/proto/Responses.java
@@ -82,6 +82,31 @@ package org.apache.calcite.avatica.proto;
      * </pre>
      */
     long getUpdateCount();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 7;</code>
+     *
+     * <pre>
+     * with no signature nor other data.
+     * </pre>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 7;</code>
+     *
+     * <pre>
+     * with no signature nor other data.
+     * </pre>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 7;</code>
+     *
+     * <pre>
+     * with no signature nor other data.
+     * </pre>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code ResultSetResponse}
@@ -176,6 +201,19 @@ package org.apache.calcite.avatica.proto;
               updateCount_ = input.readUInt64();
               break;
             }
+            case 58: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -307,6 +345,39 @@ package org.apache.calcite.avatica.proto;
       return updateCount_;
     }
 
+    public static final int METADATA_FIELD_NUMBER = 7;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 7;</code>
+     *
+     * <pre>
+     * with no signature nor other data.
+     * </pre>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 7;</code>
+     *
+     * <pre>
+     * with no signature nor other data.
+     * </pre>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 7;</code>
+     *
+     * <pre>
+     * with no signature nor other data.
+     * </pre>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -337,6 +408,9 @@ package org.apache.calcite.avatica.proto;
       if (updateCount_ != 0L) {
         output.writeUInt64(6, updateCount_);
       }
+      if (metadata_ != null) {
+        output.writeMessage(7, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -367,6 +441,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeUInt64Size(6, updateCount_);
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(7, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -502,6 +580,12 @@ package org.apache.calcite.avatica.proto;
         }
         updateCount_ = 0L;
 
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -538,6 +622,11 @@ package org.apache.calcite.avatica.proto;
           result.firstFrame_ = firstFrameBuilder_.build();
         }
         result.updateCount_ = updateCount_;
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -572,6 +661,9 @@ package org.apache.calcite.avatica.proto;
         if (other.getUpdateCount() != 0L) {
           setUpdateCount(other.getUpdateCount());
         }
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -990,6 +1082,159 @@ package org.apache.calcite.avatica.proto;
         onChanged();
         return this;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 7;</code>
+       *
+       * <pre>
+       * with no signature nor other data.
+       * </pre>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -1084,6 +1329,19 @@ package org.apache.calcite.avatica.proto;
      * </pre>
      */
     boolean getMissingStatement();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code ExecuteResponse}
@@ -1142,6 +1400,19 @@ package org.apache.calcite.avatica.proto;
               missingStatement_ = input.readBool();
               break;
             }
+            case 26: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -1218,6 +1489,27 @@ package org.apache.calcite.avatica.proto;
       return missingStatement_;
     }
 
+    public static final int METADATA_FIELD_NUMBER = 3;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -1236,6 +1528,9 @@ package org.apache.calcite.avatica.proto;
       if (missingStatement_ != false) {
         output.writeBool(2, missingStatement_);
       }
+      if (metadata_ != null) {
+        output.writeMessage(3, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -1251,6 +1546,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeBoolSize(2, missingStatement_);
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(3, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -1375,6 +1674,12 @@ package org.apache.calcite.avatica.proto;
         }
         missingStatement_ = false;
 
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -1409,6 +1714,11 @@ package org.apache.calcite.avatica.proto;
           result.results_ = resultsBuilder_.build();
         }
         result.missingStatement_ = missingStatement_;
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -1454,6 +1764,9 @@ package org.apache.calcite.avatica.proto;
         if (other.getMissingStatement() != false) {
           setMissingStatement(other.getMissingStatement());
         }
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -1758,6 +2071,123 @@ package org.apache.calcite.avatica.proto;
         onChanged();
         return this;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -1832,6 +2262,19 @@ package org.apache.calcite.avatica.proto;
      * <code>optional .StatementHandle statement = 1;</code>
      */
     org.apache.calcite.avatica.proto.Common.StatementHandleOrBuilder getStatementOrBuilder();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code PrepareResponse}
@@ -1888,6 +2331,19 @@ package org.apache.calcite.avatica.proto;
 
               break;
             }
+            case 18: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -1933,13 +2389,34 @@ package org.apache.calcite.avatica.proto;
       return getStatement();
     }
 
-    private byte memoizedIsInitialized = -1;
-    public final boolean isInitialized() {
-      byte isInitialized = memoizedIsInitialized;
-      if (isInitialized == 1) return true;
-      if (isInitialized == 0) return false;
-
-      memoizedIsInitialized = 1;
+    public static final int METADATA_FIELD_NUMBER = 2;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
       return true;
     }
 
@@ -1948,6 +2425,9 @@ package org.apache.calcite.avatica.proto;
       if (statement_ != null) {
         output.writeMessage(1, getStatement());
       }
+      if (metadata_ != null) {
+        output.writeMessage(2, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -1959,6 +2439,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(1, getStatement());
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(2, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -2080,6 +2564,12 @@ package org.apache.calcite.avatica.proto;
           statement_ = null;
           statementBuilder_ = null;
         }
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -2107,6 +2597,11 @@ package org.apache.calcite.avatica.proto;
         } else {
           result.statement_ = statementBuilder_.build();
         }
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -2125,6 +2620,9 @@ package org.apache.calcite.avatica.proto;
         if (other.hasStatement()) {
           mergeStatement(other.getStatement());
         }
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -2267,6 +2765,123 @@ package org.apache.calcite.avatica.proto;
         }
         return statementBuilder_;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -2359,6 +2974,19 @@ package org.apache.calcite.avatica.proto;
      * </pre>
      */
     boolean getMissingResults();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 4;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 4;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 4;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code FetchResponse}
@@ -2427,6 +3055,19 @@ package org.apache.calcite.avatica.proto;
               missingResults_ = input.readBool();
               break;
             }
+            case 34: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -2498,6 +3139,27 @@ package org.apache.calcite.avatica.proto;
       return missingResults_;
     }
 
+    public static final int METADATA_FIELD_NUMBER = 4;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 4;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 4;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 4;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -2519,6 +3181,9 @@ package org.apache.calcite.avatica.proto;
       if (missingResults_ != false) {
         output.writeBool(3, missingResults_);
       }
+      if (metadata_ != null) {
+        output.writeMessage(4, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -2538,6 +3203,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeBoolSize(3, missingResults_);
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(4, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -2663,6 +3332,12 @@ package org.apache.calcite.avatica.proto;
 
         missingResults_ = false;
 
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -2692,6 +3367,11 @@ package org.apache.calcite.avatica.proto;
         }
         result.missingStatement_ = missingStatement_;
         result.missingResults_ = missingResults_;
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -2716,6 +3396,9 @@ package org.apache.calcite.avatica.proto;
         if (other.getMissingResults() != false) {
           setMissingResults(other.getMissingResults());
         }
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -2934,6 +3617,123 @@ package org.apache.calcite.avatica.proto;
         onChanged();
         return this;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 4;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -3010,6 +3810,19 @@ package org.apache.calcite.avatica.proto;
      * <code>optional uint32 statement_id = 2;</code>
      */
     int getStatementId();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code CreateStatementResponse}
@@ -3066,6 +3879,19 @@ package org.apache.calcite.avatica.proto;
               statementId_ = input.readUInt32();
               break;
             }
+            case 26: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -3133,6 +3959,27 @@ package org.apache.calcite.avatica.proto;
       return statementId_;
     }
 
+    public static final int METADATA_FIELD_NUMBER = 3;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -3151,6 +3998,9 @@ package org.apache.calcite.avatica.proto;
       if (statementId_ != 0) {
         output.writeUInt32(2, statementId_);
       }
+      if (metadata_ != null) {
+        output.writeMessage(3, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -3165,6 +4015,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeUInt32Size(2, statementId_);
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(3, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -3284,6 +4138,12 @@ package org.apache.calcite.avatica.proto;
 
         statementId_ = 0;
 
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -3308,6 +4168,11 @@ package org.apache.calcite.avatica.proto;
         org.apache.calcite.avatica.proto.Responses.CreateStatementResponse result = new org.apache.calcite.avatica.proto.Responses.CreateStatementResponse(this);
         result.connectionId_ = connectionId_;
         result.statementId_ = statementId_;
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -3330,6 +4195,9 @@ package org.apache.calcite.avatica.proto;
         if (other.getStatementId() != 0) {
           setStatementId(other.getStatementId());
         }
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -3450,21 +4318,138 @@ package org.apache.calcite.avatica.proto;
         onChanged();
         return this;
       }
-      public final Builder setUnknownFields(
-          final com.google.protobuf.UnknownFieldSet unknownFields) {
-        return this;
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
       }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
 
-      public final Builder mergeUnknownFields(
-          final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
       }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
 
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
 
-      // @@protoc_insertion_point(builder_scope:CreateStatementResponse)
-    }
-
-    // @@protoc_insertion_point(class_scope:CreateStatementResponse)
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 3;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return this;
+      }
+
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return this;
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:CreateStatementResponse)
+    }
+
+    // @@protoc_insertion_point(class_scope:CreateStatementResponse)
     private static final org.apache.calcite.avatica.proto.Responses.CreateStatementResponse DEFAULT_INSTANCE;
     static {
       DEFAULT_INSTANCE = new org.apache.calcite.avatica.proto.Responses.CreateStatementResponse();
@@ -3511,6 +4496,19 @@ package org.apache.calcite.avatica.proto;
   public interface CloseStatementResponseOrBuilder extends
       // @@protoc_insertion_point(interface_extends:CloseStatementResponse)
       com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code CloseStatementResponse}
@@ -3539,6 +4537,7 @@ package org.apache.calcite.avatica.proto;
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
       this();
+      int mutable_bitField0_ = 0;
       try {
         boolean done = false;
         while (!done) {
@@ -3553,6 +4552,19 @@ package org.apache.calcite.avatica.proto;
               }
               break;
             }
+            case 10: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -3577,6 +4589,27 @@ package org.apache.calcite.avatica.proto;
               org.apache.calcite.avatica.proto.Responses.CloseStatementResponse.class, org.apache.calcite.avatica.proto.Responses.CloseStatementResponse.Builder.class);
     }
 
+    public static final int METADATA_FIELD_NUMBER = 1;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -3589,6 +4622,9 @@ package org.apache.calcite.avatica.proto;
 
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
+      if (metadata_ != null) {
+        output.writeMessage(1, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -3596,6 +4632,10 @@ package org.apache.calcite.avatica.proto;
       if (size != -1) return size;
 
       size = 0;
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -3711,6 +4751,12 @@ package org.apache.calcite.avatica.proto;
       }
       public Builder clear() {
         super.clear();
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -3733,6 +4779,11 @@ package org.apache.calcite.avatica.proto;
 
       public org.apache.calcite.avatica.proto.Responses.CloseStatementResponse buildPartial() {
         org.apache.calcite.avatica.proto.Responses.CloseStatementResponse result = new org.apache.calcite.avatica.proto.Responses.CloseStatementResponse(this);
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -3748,6 +4799,9 @@ package org.apache.calcite.avatica.proto;
 
       public Builder mergeFrom(org.apache.calcite.avatica.proto.Responses.CloseStatementResponse other) {
         if (other == org.apache.calcite.avatica.proto.Responses.CloseStatementResponse.getDefaultInstance()) return this;
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -3773,6 +4827,123 @@ package org.apache.calcite.avatica.proto;
         }
         return this;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -3834,6 +5005,19 @@ package org.apache.calcite.avatica.proto;
   public interface OpenConnectionResponseOrBuilder extends
       // @@protoc_insertion_point(interface_extends:OpenConnectionResponse)
       com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code OpenConnectionResponse}
@@ -3862,6 +5046,7 @@ package org.apache.calcite.avatica.proto;
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
       this();
+      int mutable_bitField0_ = 0;
       try {
         boolean done = false;
         while (!done) {
@@ -3876,6 +5061,19 @@ package org.apache.calcite.avatica.proto;
               }
               break;
             }
+            case 10: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -3900,6 +5098,27 @@ package org.apache.calcite.avatica.proto;
               org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse.class, org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse.Builder.class);
     }
 
+    public static final int METADATA_FIELD_NUMBER = 1;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -3912,6 +5131,9 @@ package org.apache.calcite.avatica.proto;
 
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
+      if (metadata_ != null) {
+        output.writeMessage(1, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -3919,6 +5141,10 @@ package org.apache.calcite.avatica.proto;
       if (size != -1) return size;
 
       size = 0;
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -4034,6 +5260,12 @@ package org.apache.calcite.avatica.proto;
       }
       public Builder clear() {
         super.clear();
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -4056,6 +5288,11 @@ package org.apache.calcite.avatica.proto;
 
       public org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse buildPartial() {
         org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse result = new org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse(this);
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -4071,6 +5308,9 @@ package org.apache.calcite.avatica.proto;
 
       public Builder mergeFrom(org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse other) {
         if (other == org.apache.calcite.avatica.proto.Responses.OpenConnectionResponse.getDefaultInstance()) return this;
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -4096,6 +5336,123 @@ package org.apache.calcite.avatica.proto;
         }
         return this;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -4157,6 +5514,19 @@ package org.apache.calcite.avatica.proto;
   public interface CloseConnectionResponseOrBuilder extends
       // @@protoc_insertion_point(interface_extends:CloseConnectionResponse)
       com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code CloseConnectionResponse}
@@ -4185,6 +5555,7 @@ package org.apache.calcite.avatica.proto;
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
       this();
+      int mutable_bitField0_ = 0;
       try {
         boolean done = false;
         while (!done) {
@@ -4199,6 +5570,19 @@ package org.apache.calcite.avatica.proto;
               }
               break;
             }
+            case 10: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -4223,11 +5607,32 @@ package org.apache.calcite.avatica.proto;
               org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse.class, org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse.Builder.class);
     }
 
-    private byte memoizedIsInitialized = -1;
-    public final boolean isInitialized() {
-      byte isInitialized = memoizedIsInitialized;
-      if (isInitialized == 1) return true;
-      if (isInitialized == 0) return false;
+    public static final int METADATA_FIELD_NUMBER = 1;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
 
       memoizedIsInitialized = 1;
       return true;
@@ -4235,6 +5640,9 @@ package org.apache.calcite.avatica.proto;
 
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
+      if (metadata_ != null) {
+        output.writeMessage(1, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -4242,6 +5650,10 @@ package org.apache.calcite.avatica.proto;
       if (size != -1) return size;
 
       size = 0;
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -4357,6 +5769,12 @@ package org.apache.calcite.avatica.proto;
       }
       public Builder clear() {
         super.clear();
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -4379,6 +5797,11 @@ package org.apache.calcite.avatica.proto;
 
       public org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse buildPartial() {
         org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse result = new org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse(this);
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -4394,6 +5817,9 @@ package org.apache.calcite.avatica.proto;
 
       public Builder mergeFrom(org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse other) {
         if (other == org.apache.calcite.avatica.proto.Responses.CloseConnectionResponse.getDefaultInstance()) return this;
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -4419,6 +5845,123 @@ package org.apache.calcite.avatica.proto;
         }
         return this;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 1;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -4493,6 +6036,19 @@ package org.apache.calcite.avatica.proto;
      * <code>optional .ConnectionProperties conn_props = 1;</code>
      */
     org.apache.calcite.avatica.proto.Common.ConnectionPropertiesOrBuilder getConnPropsOrBuilder();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code ConnectionSyncResponse}
@@ -4549,6 +6105,19 @@ package org.apache.calcite.avatica.proto;
 
               break;
             }
+            case 18: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -4594,6 +6163,27 @@ package org.apache.calcite.avatica.proto;
       return getConnProps();
     }
 
+    public static final int METADATA_FIELD_NUMBER = 2;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 2;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -4609,6 +6199,9 @@ package org.apache.calcite.avatica.proto;
       if (connProps_ != null) {
         output.writeMessage(1, getConnProps());
       }
+      if (metadata_ != null) {
+        output.writeMessage(2, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -4620,6 +6213,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(1, getConnProps());
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(2, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -4741,6 +6338,12 @@ package org.apache.calcite.avatica.proto;
           connProps_ = null;
           connPropsBuilder_ = null;
         }
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
         return this;
       }
 
@@ -4768,6 +6371,11 @@ package org.apache.calcite.avatica.proto;
         } else {
           result.connProps_ = connPropsBuilder_.build();
         }
+        if (metadataBuilder_ == null) {
+          result.metadata_ = metadata_;
+        } else {
+          result.metadata_ = metadataBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -4786,6 +6394,9 @@ package org.apache.calcite.avatica.proto;
         if (other.hasConnProps()) {
           mergeConnProps(other.getConnProps());
         }
+        if (other.hasMetadata()) {
+          mergeMetadata(other.getMetadata());
+        }
         onChanged();
         return this;
       }
@@ -4928,6 +6539,123 @@ package org.apache.calcite.avatica.proto;
         }
         return connPropsBuilder_;
       }
+
+      private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> metadataBuilder_;
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public boolean hasMetadata() {
+        return metadataBuilder_ != null || metadata_ != null;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+        if (metadataBuilder_ == null) {
+          return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        } else {
+          return metadataBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder setMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          metadata_ = value;
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder setMetadata(
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder builderForValue) {
+        if (metadataBuilder_ == null) {
+          metadata_ = builderForValue.build();
+          onChanged();
+        } else {
+          metadataBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder mergeMetadata(org.apache.calcite.avatica.proto.Responses.RpcMetadata value) {
+        if (metadataBuilder_ == null) {
+          if (metadata_ != null) {
+            metadata_ =
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.newBuilder(metadata_).mergeFrom(value).buildPartial();
+          } else {
+            metadata_ = value;
+          }
+          onChanged();
+        } else {
+          metadataBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public Builder clearMetadata() {
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+          onChanged();
+        } else {
+          metadata_ = null;
+          metadataBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder getMetadataBuilder() {
+        
+        onChanged();
+        return getMetadataFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+        if (metadataBuilder_ != null) {
+          return metadataBuilder_.getMessageOrBuilder();
+        } else {
+          return metadata_ == null ?
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+        }
+      }
+      /**
+       * <code>optional .RpcMetadata metadata = 2;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder> 
+          getMetadataFieldBuilder() {
+        if (metadataBuilder_ == null) {
+          metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata, org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder, org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder>(
+                  getMetadata(),
+                  getParentForChildren(),
+                  isClean());
+          metadata_ = null;
+        }
+        return metadataBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -5015,6 +6743,19 @@ package org.apache.calcite.avatica.proto;
      * <code>optional .TypedValue value = 2;</code>
      */
     org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder();
+
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    boolean hasMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata();
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder();
   }
   /**
    * Protobuf type {@code DatabasePropertyElement}
@@ -5080,6 +6821,19 @@ package org.apache.calcite.avatica.proto;
 
               break;
             }
+            case 26: {
+              org.apache.calcite.avatica.proto.Responses.RpcMetadata.Builder subBuilder = null;
+              if (metadata_ != null) {
+                subBuilder = metadata_.toBuilder();
+              }
+              metadata_ = input.readMessage(org.apache.calcite.avatica.proto.Responses.RpcMetadata.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(metadata_);
+                metadata_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -5146,6 +6900,27 @@ package org.apache.calcite.avatica.proto;
       return getValue();
     }
 
+    public static final int METADATA_FIELD_NUMBER = 3;
+    private org.apache.calcite.avatica.proto.Responses.RpcMetadata metadata_;
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public boolean hasMetadata() {
+      return metadata_ != null;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadata getMetadata() {
+      return metadata_ == null ? org.apache.calcite.avatica.proto.Responses.RpcMetadata.getDefaultInstance() : metadata_;
+    }
+    /**
+     * <code>optional .RpcMetadata metadata = 3;</code>
+     */
+    public org.apache.calcite.avatica.proto.Responses.RpcMetadataOrBuilder getMetadataOrBuilder() {
+      return getMetadata();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -5164,6 +6939,9 @@ package org.apache.calcite.avatica.proto;
       if (value_ != null) {
         output.writeMessage(2, getValue());
       }
+      if (metadata_ != null) {
+        output.writeMessage(3, getMetadata());
+      }
     }
 
     public int getSerializedSize() {
@@ -5179,6 +6957,10 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(2, getValue());
       }
+      if (metadata_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(3, getMetadata());
+      }
       memoizedSize = size;
       return size;
     }
@@ -5302,6 +7084,12 @@ package org.apache.calcite.avatica.proto;
           value_ = null;
           valueBuilder_ = null;
         }
+        if (metadataBuilder_ == null) {
+          metadata_ = null;
+        } else {
+          metadata_ = null;
+          me

<TRUNCATED>