You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kyuubi.apache.org by ul...@apache.org on 2021/12/22 10:17:22 UTC

[incubator-kyuubi] branch master updated: [KYUUBI #1575] Implement api: /${version}/operations/${operation_identifier}/resultsetmetadata

This is an automated email from the ASF dual-hosted git repository.

ulyssesyou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-kyuubi.git


The following commit(s) were added to refs/heads/master by this push:
     new c972139  [KYUUBI #1575] Implement api: /${version}/operations/${operation_identifier}/resultsetmetadata
c972139 is described below

commit c972139b5128207213ebe372bfe206ac88233b6e
Author: simon <zh...@cvte.com>
AuthorDate: Wed Dec 22 18:17:08 2021 +0800

    [KYUUBI #1575] Implement api: /${version}/operations/${operation_identifier}/resultsetmetadata
    
    ### _Why are the changes needed?_
    #1575
    Implement api: /${version}/operations/${operation_identifier}/resultsetmetadata
    
    - /${version}/operations/${operation_identifier}/resultsetmetadata
      - mapping: ICLIService#getResultSetMetadata
      - desc: get the table schema of the result set via the given operation identifier
      - method: GET
      - params: none
      - returns: an instance of TableSchema
    
    ### _How was this patch tested?_
    - [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible
    
    - [ ] Add screenshots for manual tests if appropriate
    
    - [ ] [Run test](https://kyuubi.readthedocs.io/en/latest/develop_tools/testing.html#running-tests) locally before make a pull request
    
    Closes #1576 from simon824/api1.
    
    Closes #1575
    
    ecc976d1 [simon] reorder
    0ef2accf [simon] add
    ea635da4 [simon] fix
    310ad983 [simon] resultsetmetadata
    595294fa [simon] init
    
    Authored-by: simon <zh...@cvte.com>
    Signed-off-by: ulysses-you <ul...@apache.org>
---
 .../kyuubi/server/api/v1/OperationsResource.scala  | 40 ++++++++++++++++++++++
 .../org/apache/kyuubi/server/api/v1/dto.scala      | 10 ++++++
 .../server/api/v1/OperationsResourceSuite.scala    | 10 ++++++
 3 files changed, 60 insertions(+)

diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/OperationsResource.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/OperationsResource.scala
index 17abf51..f3a5c4c 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/OperationsResource.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/OperationsResource.scala
@@ -20,11 +20,13 @@ package org.apache.kyuubi.server.api.v1
 import javax.ws.rs.{GET, Path, PathParam, Produces, _}
 import javax.ws.rs.core.{MediaType, Response}
 
+import scala.collection.JavaConverters.asScalaBufferConverter
 import scala.util.control.NonFatal
 
 import io.swagger.v3.oas.annotations.media.Content
 import io.swagger.v3.oas.annotations.responses.ApiResponse
 import io.swagger.v3.oas.annotations.tags.Tag
+import org.apache.hive.service.rpc.thrift.TTypeQualifierValue
 
 import org.apache.kyuubi.KyuubiSQLException
 import org.apache.kyuubi.events.KyuubiOperationEvent
@@ -81,4 +83,42 @@ private[v1] class OperationsResource extends ApiRequestContext {
           s"for operation handle $operationHandleStr")
     }
   }
+
+  @ApiResponse(
+    responseCode = "200",
+    content = Array(new Content(
+      mediaType = MediaType.APPLICATION_JSON)),
+    description =
+      "get result set metadata")
+  @GET
+  @Path("{operationHandle}/resultsetmetadata")
+  def getResultSetMetadata(
+      @PathParam("operationHandle") operationHandleStr: String): ResultSetMetaData = {
+    try {
+      val operationHandle = parseOperationHandle(operationHandleStr)
+      ResultSetMetaData(
+        backendService.getResultSetMetadata(operationHandle).getColumns.asScala.map(c => {
+          val tPrimitiveTypeEntry = c.getTypeDesc.getTypes.get(0).getPrimitiveEntry
+          var precision = 0
+          var scale = 0
+          if (tPrimitiveTypeEntry.getTypeQualifiers != null) {
+            val qualifiers = tPrimitiveTypeEntry.getTypeQualifiers.getQualifiers
+            val defaultValue = TTypeQualifierValue.i32Value(0);
+            precision = qualifiers.getOrDefault("precision", defaultValue).getI32Value
+            scale = qualifiers.getOrDefault("scale", defaultValue).getI32Value
+          }
+          ColumnDesc(
+            c.getColumnName,
+            tPrimitiveTypeEntry.getType.toString,
+            c.getPosition,
+            precision,
+            scale,
+            c.getComment)
+        }))
+    } catch {
+      case NonFatal(_) =>
+        throw new NotFoundException(
+          s"Error getting result set metadata for operation handle $operationHandleStr")
+    }
+  }
 }
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/dto.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/dto.scala
index 87f5566..5917906 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/dto.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/dto.scala
@@ -69,3 +69,13 @@ case class GetFunctionsRequest(
     functionName: String)
 
 case class OpActionRequest(action: String)
+
+case class ResultSetMetaData(columns: Seq[ColumnDesc])
+
+case class ColumnDesc(
+    columnName: String,
+    dataType: String,
+    columnIndex: Int,
+    precision: Int,
+    scale: Int,
+    comment: String)
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/OperationsResourceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/OperationsResourceSuite.scala
index a9d04f5..b0bca33 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/OperationsResourceSuite.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/OperationsResourceSuite.scala
@@ -78,7 +78,17 @@ class OperationsResourceSuite extends KyuubiFunSuite with RestFrontendTestHelper
       response = webTarget.path(s"api/v1/operations/$opHandleStr/event")
         .request(MediaType.APPLICATION_JSON_TYPE).get()
       assert(404 == response.getStatus)
+    }
+  }
 
+  test("test get result set metadata") {
+    withKyuubiRestServer { (fe, _, _, webTarget: WebTarget) =>
+      val opHandleStr = getOpHandleStr(fe, OperationType.EXECUTE_STATEMENT)
+      val response = webTarget.path(s"api/v1/operations/$opHandleStr/resultsetmetadata")
+        .request(MediaType.APPLICATION_JSON_TYPE).get()
+      assert(200 == response.getStatus)
+      val resultSetMetaData = response.readEntity(classOf[ResultSetMetaData])
+      assert(resultSetMetaData.columns.head.columnName.equals("Result"))
     }
   }