Skip to content

Conversation

@tanjialiang
Copy link
Contributor

@tanjialiang tanjialiang commented Nov 7, 2025

Summary: Currently the velox exception translation is through global static methods, not extensible. Use cases arises when we want additional error types exposed from not within presto/velox stack. This change makes the translation layer a global singleton, similar to BaseStatsReporter in velox, creating flexibility to extend and customize.

Differential Revision: D86562978

== NO RELEASE NOTE ==

@tanjialiang tanjialiang requested review from a team as code owners November 7, 2025 23:19
@prestodb-ci prestodb-ci added the from:Meta PR from Meta label Nov 7, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 7, 2025

Reviewer's Guide

This PR replaces the static global translation map with an instance‐based, singleton translator that is populated via registerError in its constructor, introduces folly::Singleton and inline helper APIs for extensible exception translation, converts translate methods to non‐static instance methods, and updates all call sites and tests to use the new translator.

Class diagram for extensible exception translation

classDiagram
class VeloxToPrestoExceptionTranslator {
  +VeloxToPrestoExceptionTranslator()
  +~VeloxToPrestoExceptionTranslator()
  +translate(const velox::VeloxException& e) const : protocol::ExecutionFailureInfo
  +translate(const std::exception& e) const : protocol::ExecutionFailureInfo
  +testingErrorMap() const : ErrorCodeMap
  #registerError(const std::string& errorSource, const std::string& errorCode, const protocol::ErrorCode& prestoErrorCode)
  #errorMap_ : ErrorCodeMap
}

class protocol_ExecutionFailureInfo
class velox_VeloxException
class std_exception

VeloxToPrestoExceptionTranslator --> protocol_ExecutionFailureInfo : returns
VeloxToPrestoExceptionTranslator --> velox_VeloxException : uses
VeloxToPrestoExceptionTranslator --> std_exception : uses

class folly_Singleton_VeloxToPrestoExceptionTranslator {
}

folly_Singleton_VeloxToPrestoExceptionTranslator --> VeloxToPrestoExceptionTranslator : manages singleton instance

class translateToPrestoException {
  +translateToPrestoException(const velox::VeloxException& e) : protocol::ExecutionFailureInfo
  +translateToPrestoException(const std::exception& e) : protocol::ExecutionFailureInfo
}

translateToPrestoException --> folly_Singleton_VeloxToPrestoExceptionTranslator : gets instance
translateToPrestoException --> VeloxToPrestoExceptionTranslator : calls translate()
Loading

Flow diagram for exception translation API usage

flowchart TD
    A["Exception thrown (VeloxException or std::exception)"] --> B["translateToPrestoException(e)"]
    B --> C["folly::Singleton<VeloxToPrestoExceptionTranslator>::try_get_fast()"]
    C --> D["VeloxToPrestoExceptionTranslator::translate(e)"]
    D --> E["protocol::ExecutionFailureInfo"]
Loading

File-Level Changes

Change Details Files
Migrate from static translateMap to dynamic registration
  • Remove translateMap static function and hardcoded map initialization
  • Add errorMap_ member and registerError method to store mappings
  • Populate errorMap_ in VeloxToPrestoExceptionTranslator constructor via registerError
presto-native-execution/presto_cpp/main/common/Exception.cpp
presto-native-execution/presto_cpp/main/common/Exception.h
Introduce singleton translator and inline helper APIs
  • Include folly/Singleton and define translateToPrestoException inline functions
  • Register VeloxToPrestoExceptionTranslator with folly::Singleton in PrestoMain
presto-native-execution/presto_cpp/main/common/Exception.h
presto-native-execution/presto_cpp/main/PrestoMain.cpp
Convert translate methods to non-static instance methods and update call sites
  • Change translate signatures to virtual const methods and remove static qualifiers
  • Use errorMap_ instead of translateMap in translate implementations
  • Replace direct static calls with translateToPrestoException or translator->translate in PlanConversion, PrestoTask, and tests
presto-native-execution/presto_cpp/main/common/Exception.cpp
presto-native-execution/presto_cpp/main/common/Exception.h
presto-native-execution/presto_cpp/main/types/VeloxPlanConversion.cpp
presto-native-execution/presto_cpp/main/PrestoTask.cpp
presto-native-execution/presto_cpp/main/common/tests/CommonTest.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `presto-native-execution/presto_cpp/main/common/tests/CommonTest.cpp:29-27` </location>
<code_context>
+        []() { return new facebook::presto::VeloxToPrestoExceptionTranslator(); });
+}
+
 TEST(VeloxToPrestoExceptionTranslatorTest, exceptionTranslation) {
   FLAGS_velox_exception_user_stacktrace_enabled = true;
   for (const bool withContext : {false, true}) {
</code_context>

<issue_to_address>
**suggestion (testing):** Missing test for duplicate error registration in VeloxToPrestoExceptionTranslator.

Please add a test that registers a duplicate error code and checks that the expected exception or assertion is raised, confirming the singleton's registration logic works correctly.

Suggested implementation:

```cpp
TEST(VeloxToPrestoExceptionTranslatorTest, exceptionTranslation) {
  FLAGS_velox_exception_user_stacktrace_enabled = true;
  for (const bool withContext : {false, true}) {
        EXPECT_EQ(e.errorSource(), error_source::kErrorSourceUser);
        EXPECT_EQ(e.errorCode(), velox::error_code::kArithmeticError);

        auto translator = folly::Singleton<
            VeloxToPrestoExceptionTranslator>::try_get();
        ASSERT_NE(translator, nullptr);
        auto failureInfo = translateToPrestoException(e);
        EXPECT_EQ(failureInfo.type, e.exceptionName());
        EXPECT_EQ(failureInfo.errorLocation.lineNumber, e.line());
}

TEST(VeloxToPrestoExceptionTranslatorTest, duplicateErrorRegistration) {
  auto* translator = folly::Singleton<VeloxToPrestoExceptionTranslator>::try_get();
  ASSERT_NE(translator, nullptr);

  // Register a custom error code.
  const std::string errorCode = "DUPLICATE_ERROR";
  const std::string exceptionName = "DuplicateException";
  translator->registerErrorCode(errorCode, exceptionName);

  // Attempt to register the same error code again and expect an exception/assertion.
  EXPECT_THROW(
      translator->registerErrorCode(errorCode, exceptionName),
      std::runtime_error
  );
}

```

- Ensure that `VeloxToPrestoExceptionTranslator::registerErrorCode` throws a `std::runtime_error` (or the appropriate exception type) when a duplicate error code is registered. If it currently asserts or throws a different exception, adjust the test and/or implementation accordingly.
- If the singleton is reset between tests, you may need to clear or reinitialize the error code registry before/after this test.
</issue_to_address>

### Comment 2
<location> `presto-native-execution/presto_cpp/main/common/tests/CommonTest.cpp:125-131` </location>
<code_context>
   }

   std::runtime_error stdRuntimeError("Test error message");
-  auto failureInfo =
-      VeloxToPrestoExceptionTranslator::translate((stdRuntimeError));
+  auto translator = folly::Singleton<
+      VeloxToPrestoExceptionTranslator>::try_get();
+  ASSERT_NE(translator, nullptr);
+  auto failureInfo = translateToPrestoException((stdRuntimeError));
   EXPECT_EQ(failureInfo.type, "std::exception");
   EXPECT_EQ(failureInfo.errorLocation.lineNumber, 1);
   EXPECT_EQ(failureInfo.errorCode.name, "GENERIC_INTERNAL_ERROR");
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding tests for exception translation when stack trace is not available.

Please add a test where VeloxException lacks a stack trace and confirm the translated error either omits or properly handles the stack field.

```suggestion
    auto translator = folly::Singleton<
        VeloxToPrestoExceptionTranslator>::try_get();
    ASSERT_NE(translator, nullptr);
    auto failureInfo = translateToPrestoException(e);
    EXPECT_EQ(failureInfo.type, e.exceptionName());
    EXPECT_EQ(failureInfo.errorLocation.lineNumber, e.line());
    EXPECT_EQ(failureInfo.errorCode.name, "GENERIC_USER_ERROR");
  }

  // Test translation of VeloxException without stack trace.
  TEST(CommonTest, VeloxExceptionWithoutStackTrace) {
    // Construct a VeloxException without a stack trace.
    velox::VeloxException e(
        "No stack trace error",
        velox::error_code::kInvalidArgument,
        error_source::kErrorSourceUser,
        __FILE__,
        123, // example line number
        nullptr // No stack trace
    );

    auto translator = folly::Singleton<
        VeloxToPrestoExceptionTranslator>::try_get();
    ASSERT_NE(translator, nullptr);
    auto failureInfo = translateToPrestoException(e);

    EXPECT_EQ(failureInfo.type, e.exceptionName());
    EXPECT_EQ(failureInfo.errorLocation.lineNumber, 123);
    EXPECT_EQ(failureInfo.errorCode.name, "GENERIC_USER_ERROR");
    // Check that stack field is either omitted, empty, or handled gracefully.
    // This depends on the implementation of translateToPrestoException.
    // For example, if stack is a string:
    EXPECT_TRUE(failureInfo.stack.empty() || failureInfo.stack == "" || failureInfo.stack == std::nullopt);
  }
```
</issue_to_address>

### Comment 3
<location> `presto-native-execution/presto_cpp/main/common/tests/CommonTest.cpp:31-27` </location>
<code_context>
+
 TEST(VeloxToPrestoExceptionTranslatorTest, exceptionTranslation) {
   FLAGS_velox_exception_user_stacktrace_enabled = true;
   for (const bool withContext : {false, true}) {
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding tests for unknown error sources and codes.

Please add a test for unknown error sources or codes to confirm the fallback logic returns the expected generic error.

Suggested implementation:

```cpp
TEST(VeloxToPrestoExceptionTranslatorTest, exceptionTranslation) {
  FLAGS_velox_exception_user_stacktrace_enabled = true;
  for (const bool withContext : {false, true}) {
        EXPECT_EQ(e.errorSource(), error_source::kErrorSourceUser);
        EXPECT_EQ(e.errorCode(), velox::error_code::kArithmeticError);

        auto translator = folly::Singleton<
            VeloxToPrestoExceptionTranslator>::try_get();
        ASSERT_NE(translator, nullptr);
        auto failureInfo = translateToPrestoException(e);
        EXPECT_EQ(failureInfo.type, e.exceptionName());
        EXPECT_EQ(failureInfo.errorLocation.lineNumber, e.line());
  }
}

// Test for unknown error source and code to confirm fallback logic.
TEST(VeloxToPrestoExceptionTranslatorTest, unknownErrorSourceAndCode) {
  // Create a Velox exception with unknown error source and code.
  velox::VeloxException unknownException(
      "Unknown error",
      velox::error_source::kErrorSourceUnknown, // Unknown error source
      velox::error_code::kUnknown,              // Unknown error code
      __FILE__,
      __LINE__);

  auto translator = folly::Singleton<
      VeloxToPrestoExceptionTranslator>::try_get();
  ASSERT_NE(translator, nullptr);
  auto failureInfo = translateToPrestoException(unknownException);

  // Check that the fallback logic returns the expected generic error type/code.
  EXPECT_EQ(failureInfo.type, "UNKNOWN"); // Or whatever the fallback type is
  EXPECT_EQ(failureInfo.errorCode, "GENERIC_INTERNAL_ERROR"); // Or the expected fallback code
  EXPECT_EQ(failureInfo.message, "Unknown error");
}

```

- You may need to adjust the expected values for `failureInfo.type` and `failureInfo.errorCode` to match your actual fallback logic. Replace "UNKNOWN" and "GENERIC_INTERNAL_ERROR" with the correct values if your implementation uses different strings.
- If your `translateToPrestoException` function or `VeloxException` constructor requires additional parameters, please add them accordingly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

folly::Singleton<facebook::presto::VeloxToPrestoExceptionTranslator>
exceptionTranslatorSingleton(
[]() { return new facebook::presto::VeloxToPrestoExceptionTranslator(); });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Missing test for duplicate error registration in VeloxToPrestoExceptionTranslator.

Please add a test that registers a duplicate error code and checks that the expected exception or assertion is raised, confirming the singleton's registration logic works correctly.

Suggested implementation:

TEST(VeloxToPrestoExceptionTranslatorTest, exceptionTranslation) {
  FLAGS_velox_exception_user_stacktrace_enabled = true;
  for (const bool withContext : {false, true}) {
        EXPECT_EQ(e.errorSource(), error_source::kErrorSourceUser);
        EXPECT_EQ(e.errorCode(), velox::error_code::kArithmeticError);

        auto translator = folly::Singleton<
            VeloxToPrestoExceptionTranslator>::try_get();
        ASSERT_NE(translator, nullptr);
        auto failureInfo = translateToPrestoException(e);
        EXPECT_EQ(failureInfo.type, e.exceptionName());
        EXPECT_EQ(failureInfo.errorLocation.lineNumber, e.line());
}

TEST(VeloxToPrestoExceptionTranslatorTest, duplicateErrorRegistration) {
  auto* translator = folly::Singleton<VeloxToPrestoExceptionTranslator>::try_get();
  ASSERT_NE(translator, nullptr);

  // Register a custom error code.
  const std::string errorCode = "DUPLICATE_ERROR";
  const std::string exceptionName = "DuplicateException";
  translator->registerErrorCode(errorCode, exceptionName);

  // Attempt to register the same error code again and expect an exception/assertion.
  EXPECT_THROW(
      translator->registerErrorCode(errorCode, exceptionName),
      std::runtime_error
  );
}
  • Ensure that VeloxToPrestoExceptionTranslator::registerErrorCode throws a std::runtime_error (or the appropriate exception type) when a duplicate error code is registered. If it currently asserts or throws a different exception, adjust the test and/or implementation accordingly.
  • If the singleton is reset between tests, you may need to clear or reinitialize the error code registry before/after this test.

xiaoxmeng
xiaoxmeng previously approved these changes Nov 7, 2025
@tanjialiang
Copy link
Contributor Author

@majetideepak I'm not sure if this change might affect your use case. Could you take a look to make sure nothing breaks from your side? Thanks!

@tanjialiang tanjialiang changed the title refactor: Refactor exception translation to be extensible refactor(native): Refactor exception translation to be extensible Nov 8, 2025
…6563)

Summary:

Currently the velox exception translation is through global static methods, not extensible. Use cases arises when we want additional error types exposed from not within presto/velox stack. This change makes the translation layer a global singleton, similar to BaseStatsReporter in velox, creating flexibility to extend and customize.

Reviewed By: xiaoxmeng

Differential Revision: D86562978
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants