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

cheddar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 7e2cf35d7b Fix compatibility issue with SqlTaskResource (#14466)
7e2cf35d7b is described below

commit 7e2cf35d7b0485b5fe5abeb021c5811ee812b0c7
Author: imply-cheddar <86940447+imply-ched...@users.noreply.github.com>
AuthorDate: Fri Jun 23 17:15:32 2023 +0900

    Fix compatibility issue with SqlTaskResource (#14466)
    
    * Fix compatibility issue with SqlTaskResource
    
    The DruidException changes broke the response format
    for errors coming back from the SqlTaskResource, so fix those
---
 .../org/apache/druid/msq/sql/SqlTaskResource.java  | 91 ++++++++--------------
 .../org/apache/druid/msq/sql/SqlTaskStatus.java    | 10 +--
 .../apache/druid/msq/sql/SqlTaskStatusTest.java    | 18 +++--
 .../org/apache/druid/error/DruidException.java     |  4 +
 .../org/apache/druid/query/BadQueryException.java  |  2 -
 5 files changed, 52 insertions(+), 73 deletions(-)

diff --git 
a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskResource.java
 
b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskResource.java
index d270963db4..dd4ec4d2b3 100644
--- 
a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskResource.java
+++ 
b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskResource.java
@@ -23,22 +23,16 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.io.CountingOutputStream;
 import com.google.inject.Inject;
-import org.apache.druid.common.exception.SanitizableException;
 import org.apache.druid.error.DruidException;
 import org.apache.druid.error.ErrorResponse;
+import org.apache.druid.error.QueryExceptionCompat;
 import org.apache.druid.guice.annotations.MSQ;
 import org.apache.druid.indexer.TaskState;
 import org.apache.druid.java.util.common.guava.Sequence;
 import org.apache.druid.java.util.common.guava.Yielder;
 import org.apache.druid.java.util.common.guava.Yielders;
 import org.apache.druid.java.util.common.logger.Logger;
-import org.apache.druid.query.BadQueryException;
-import org.apache.druid.query.QueryCapacityExceededException;
 import org.apache.druid.query.QueryException;
-import org.apache.druid.query.QueryInterruptedException;
-import org.apache.druid.query.QueryTimeoutException;
-import org.apache.druid.query.QueryUnsupportedException;
-import org.apache.druid.query.ResourceLimitExceededException;
 import org.apache.druid.server.QueryResponse;
 import org.apache.druid.server.initialization.ServerConfig;
 import org.apache.druid.server.security.Access;
@@ -47,7 +41,6 @@ import org.apache.druid.server.security.AuthorizerMapper;
 import org.apache.druid.server.security.ForbiddenException;
 import org.apache.druid.sql.DirectStatement;
 import org.apache.druid.sql.HttpStatement;
-import org.apache.druid.sql.SqlPlanningException;
 import org.apache.druid.sql.SqlRowTransformer;
 import org.apache.druid.sql.SqlStatementFactory;
 import org.apache.druid.sql.http.ResultFormat;
@@ -63,7 +56,6 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.StreamingOutput;
 import java.io.IOException;
 import java.util.Collections;
@@ -162,43 +154,32 @@ public class SqlTaskResource
     }
     catch (DruidException e) {
       stmt.reporter().failed(e);
-      return Response.status(e.getStatusCode())
-                     .type(MediaType.APPLICATION_JSON_TYPE)
-                     .entity(new ErrorResponse(e))
-                     .build();
+      return buildNonOkResponse(sqlQueryId, e);
     }
-    // Kitchen-sinking the errors since they are all unchecked.
-    // Just copied from SqlResource.
-    catch (QueryCapacityExceededException cap) {
-      stmt.reporter().failed(cap);
-      return buildNonOkResponse(QueryCapacityExceededException.STATUS_CODE, 
cap, sqlQueryId);
-    }
-    catch (QueryUnsupportedException unsupported) {
-      stmt.reporter().failed(unsupported);
-      return buildNonOkResponse(QueryUnsupportedException.STATUS_CODE, 
unsupported, sqlQueryId);
-    }
-    catch (QueryTimeoutException timeout) {
-      stmt.reporter().failed(timeout);
-      return buildNonOkResponse(QueryTimeoutException.STATUS_CODE, timeout, 
sqlQueryId);
-    }
-    catch (SqlPlanningException | ResourceLimitExceededException e) {
-      stmt.reporter().failed(e);
-      return buildNonOkResponse(BadQueryException.STATUS_CODE, e, sqlQueryId);
+    catch (QueryException queryException) {
+      stmt.reporter().failed(queryException);
+      final DruidException underlyingException = 
DruidException.fromFailure(new QueryExceptionCompat(queryException));
+      return buildNonOkResponse(sqlQueryId, underlyingException);
     }
     catch (ForbiddenException e) {
-      // No request logs for forbidden queries; same as SqlResource
-      throw (ForbiddenException) 
serverConfig.getErrorResponseTransformStrategy()
-                                             .transformIfNeeded(e); // let 
ForbiddenExceptionMapper handle this
+      log.debug("Got forbidden request for reason [%s]", e.getErrorMessage());
+      return buildNonOkResponse(
+          "forbidden",
+          DruidException.forPersona(DruidException.Persona.USER)
+                        .ofCategory(DruidException.Category.FORBIDDEN)
+                        .build(Access.DEFAULT_ERROR_MESSAGE)
+      );
     }
-    // Calcite throws a java.lang.AssertionError which is type Error not 
Exception. Using Throwable catches both.
-    catch (Throwable e) {
+    // Calcite throws java.lang.AssertionError at various points in 
planning/validation.
+    catch (AssertionError | Exception e) {
       stmt.reporter().failed(e);
       log.noStackTrace().warn(e, "Failed to handle query: %s", sqlQueryId);
 
       return buildNonOkResponse(
-          Status.INTERNAL_SERVER_ERROR.getStatusCode(),
-          QueryInterruptedException.wrapIfNeeded(e),
-          sqlQueryId
+          sqlQueryId,
+          DruidException.forPersona(DruidException.Persona.DEVELOPER)
+                        .ofCategory(DruidException.Category.UNCATEGORIZED)
+                        .build(e.getMessage())
       );
     }
     finally {
@@ -237,12 +218,16 @@ public class SqlTaskResource
     yielder.close();
 
     if (taskId == null) {
-      // Note: no ID to include in error: that is the problem we're reporting.
-      return genericError(
-          Response.Status.INTERNAL_SERVER_ERROR,
-          "Internal error",
-          "Failed to issue query task",
-          null
+      // Note: no ID to include in error: that is the problem we're reporting. 
 It would be really nice to know
+      // why we don't have an ID or more information about why things failed.  
Hopefully that gets returned to the
+      // user through a DruidExcpetion that makes it out of this code and this 
code never actually gets executed.
+      // Using a defensive exception just to report something with the opes 
that any time this actually happens, the
+      // fix is to make error reporting somewhere that actually understands 
more about why it failed.
+      return buildNonOkResponse(
+          null,
+          DruidException.forPersona(DruidException.Persona.DEVELOPER)
+                        .ofCategory(DruidException.Category.DEFENSIVE)
+                        .build("Failed to issue query task")
       );
     }
 
@@ -252,6 +237,7 @@ public class SqlTaskResource
         .build();
   }
 
+  @SuppressWarnings("UnstableApiUsage")
   private Response buildStandardResponse(
       Sequence<Object[]> sequence,
       SqlQuery sqlQuery,
@@ -316,22 +302,11 @@ public class SqlTaskResource
     }
   }
 
-  private Response buildNonOkResponse(int status, SanitizableException e, 
String sqlQueryId)
-  {
-    QueryException cleaned = (QueryException) serverConfig
-        .getErrorResponseTransformStrategy()
-        .transformIfNeeded(e);
-    return Response
-        .status(status)
-        .entity(new SqlTaskStatus(sqlQueryId, TaskState.FAILED, cleaned))
-        .build();
-  }
-
-  private Response genericError(Response.Status status, String code, String 
msg, String id)
+  private Response buildNonOkResponse(String sqlQueryId, DruidException 
exception)
   {
     return Response
-        .status(status)
-        .entity(new SqlTaskStatus(id, TaskState.FAILED, new 
QueryException("FAILED", msg, null, null)))
+        .status(exception.getStatusCode())
+        .entity(new SqlTaskStatus(sqlQueryId, TaskState.FAILED, new 
ErrorResponse(exception)))
         .build();
   }
 }
diff --git 
a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskStatus.java
 
b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskStatus.java
index d47533315e..9fa14ee994 100644
--- 
a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskStatus.java
+++ 
b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/SqlTaskStatus.java
@@ -23,8 +23,8 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
+import org.apache.druid.error.ErrorResponse;
 import org.apache.druid.indexer.TaskState;
-import org.apache.druid.query.QueryException;
 
 import javax.annotation.Nullable;
 import java.util.Objects;
@@ -37,13 +37,13 @@ public class SqlTaskStatus
   private final String taskId;
   private final TaskState state;
   @Nullable
-  private final QueryException error;
+  private final ErrorResponse error;
 
   @JsonCreator
   public SqlTaskStatus(
       @JsonProperty("taskId") final String taskId,
       @JsonProperty("state") final TaskState state,
-      @JsonProperty("error") @Nullable final QueryException error
+      @JsonProperty("error") @Nullable final ErrorResponse error
   )
   {
     this.taskId = Preconditions.checkNotNull(taskId, "taskId");
@@ -66,7 +66,7 @@ public class SqlTaskStatus
   @Nullable
   @JsonProperty
   @JsonInclude(JsonInclude.Include.NON_NULL)
-  public QueryException getError()
+  public ErrorResponse getError()
   {
     return error;
   }
@@ -98,7 +98,7 @@ public class SqlTaskStatus
     return "SqlTaskStatus{" +
            "taskId='" + taskId + '\'' +
            ", state=" + state +
-           ", error=" + error +
+           ", error=" + (error == null ? "null" : error.getAsMap()) +
            '}';
   }
 }
diff --git 
a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/SqlTaskStatusTest.java
 
b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/SqlTaskStatusTest.java
index 03efc96e6d..301f91ce8d 100644
--- 
a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/SqlTaskStatusTest.java
+++ 
b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/SqlTaskStatusTest.java
@@ -21,8 +21,9 @@ package org.apache.druid.msq.sql;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import nl.jqno.equalsverifier.EqualsVerifier;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.error.ErrorResponse;
 import org.apache.druid.indexer.TaskState;
-import org.apache.druid.query.QueryException;
 import org.apache.druid.segment.TestHelper;
 import org.junit.Assert;
 import org.junit.Test;
@@ -34,22 +35,23 @@ public class SqlTaskStatusTest
   {
     final ObjectMapper mapper = TestHelper.makeJsonMapper();
 
+    DruidException underlyingException = 
DruidException.forPersona(DruidException.Persona.DEVELOPER)
+        .ofCategory(DruidException.Category.INVALID_INPUT)
+        .build("error message");
+
     final SqlTaskStatus status = new SqlTaskStatus(
         "taskid",
         TaskState.FAILED,
-        new QueryException(
-            "error code",
-            "error message",
-            "error class",
-            "host"
-        )
+        new ErrorResponse(underlyingException)
     );
 
     final SqlTaskStatus status2 = 
mapper.readValue(mapper.writeValueAsString(status), SqlTaskStatus.class);
 
     Assert.assertEquals(status.getTaskId(), status2.getTaskId());
     Assert.assertEquals(status.getState(), status2.getState());
-    Assert.assertEquals(status.getError().getErrorCode(), 
status2.getError().getErrorCode());
+    Assert.assertNotNull(status.getError());
+    Assert.assertNotNull(status2.getError());
+    Assert.assertEquals(status.getError().getAsMap(), 
status2.getError().getAsMap());
   }
 
   @Test
diff --git 
a/processing/src/main/java/org/apache/druid/error/DruidException.java 
b/processing/src/main/java/org/apache/druid/error/DruidException.java
index 6acedf55fd..81a7939ec4 100644
--- a/processing/src/main/java/org/apache/druid/error/DruidException.java
+++ b/processing/src/main/java/org/apache/druid/error/DruidException.java
@@ -315,6 +315,10 @@ public class DruidException extends RuntimeException
      * Means that the error is a problem with authorization.
      */
     UNAUTHORIZED(401),
+    /**
+     * Means that an action that was attempted is forbidden
+     */
+    FORBIDDEN(403),
     /**
      * Means that some capacity limit was exceeded, this could be due to 
throttling or due to some system limit
      */
diff --git 
a/processing/src/main/java/org/apache/druid/query/BadQueryException.java 
b/processing/src/main/java/org/apache/druid/query/BadQueryException.java
index e627c966ad..dc498e85e9 100644
--- a/processing/src/main/java/org/apache/druid/query/BadQueryException.java
+++ b/processing/src/main/java/org/apache/druid/query/BadQueryException.java
@@ -26,8 +26,6 @@ package org.apache.druid.query;
  */
 public abstract class BadQueryException extends QueryException
 {
-  public static final int STATUS_CODE = 400;
-
   protected BadQueryException(String errorCode, String errorMessage, String 
errorClass)
   {
     this(errorCode, errorMessage, errorClass, null);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@druid.apache.org
For additional commands, e-mail: commits-h...@druid.apache.org

Reply via email to