Skip to content

Conversation

@gertjanal
Copy link
Contributor

@gertjanal gertjanal commented Oct 23, 2025

Description

External clients might use the EXECUTE IMMEDIATE '..' query wrapper. This type of query is used for small and quick queries, that should be answered within seconds (to select partition info for a table for example). When using resource groups, these EXECUTE IMMEDIATE queries are scheduled as normal queries, as the QueryPreparer unwraps the statement and forgets that is was a EXECUTE IMMEDIATE query. This results in queued small queries and unresponsive user interfaces.

With this PR, a selector can be created to match all EXECUTE IMMEDIATE queries by setting "isExecuteImmediate": true. The selector can send the query to a priority resource group so that the query is handled directly.

Additional context and related issues

I added the isExecuteImmediate to the PreparedQuery, as the QueryPreparer unwraps the ExecuteImmediateStatement and forgets it's purpose. I considered keeping the PreparedQuery and adding a boolean isExecuteImmediate = query.toLowerCase().trim().startsWith("EXECUTE IMMEDIATE "); to the DispatchManager, but I don't think the query should be "parsed" twice.

Release notes

( ) This is not user-visible or is docs only, and no release notes are required.
( X ) Release notes are required. Please propose a release note for me.
( ) Release notes are required, with the following suggested text:

## Resource groups
* When using the resource group database, the table `selectors` should be extended with the column `is_execute_immediate VARCHAR(6)` and contain `NULL`, `"true"` or `"false"`

Summary by Sourcery

Add support for matching EXECUTE IMMEDIATE queries in resource group selectors by introducing an isExecuteImmediate flag and propagating it through query preparation, dispatch, configuration, and storage.

New Features:

  • Introduce isExecuteImmediate flag in PreparedQuery and SelectionCriteria
  • Add isExecuteImmediate property to SelectorSpec, StaticSelector, and dispatch logic to route EXECUTE IMMEDIATE queries
  • Persist is_execute_immediate column in selectors table for resource group configuration

Enhancements:

  • Propagate isExecuteImmediate flag through DispatchManager to apply selectors during query submission

Build:

  • Update selectors table schema to include is_execute_immediate column

Documentation:

  • Document the isExecuteImmediate selector property in resource group documentation

Tests:

  • Add StaticSelector and DAO tests for isExecuteImmediate matching

…urce group DB update for table `selectors`: `is_execute_immediate VARCHAR(6)`
@cla-bot cla-bot bot added the cla-signed label Oct 23, 2025
@sourcery-ai
Copy link

sourcery-ai bot commented Oct 23, 2025

Reviewer's Guide

This PR introduces a new boolean isExecuteImmediate flag to the query selection pipeline—captured during query preparation, carried through dispatch, exposed in SelectionCriteria, surfaced in selector specifications and persisted in the selectors table—and updates selector matching and configuration managers to filter on this flag.

ER diagram for selectors table with is_execute_immediate column

erDiagram
    SELECTORS {
        BIGINT resource_group_id
        INT priority
        VARCHAR user_regex
        VARCHAR source_regex
        VARCHAR original_user_regex
        VARCHAR authenticated_user_regex
        VARCHAR query_type
        VARCHAR client_tags
        VARCHAR selector_resource_estimate
        VARCHAR user_group_regex
        VARCHAR is_execute_immediate
    }
    RESOURCE_GROUPS {
        BIGINT resource_group_id
        VARCHAR environment
    }
    SELECTORS ||--o{ RESOURCE_GROUPS : "resource_group_id"
Loading

Class diagram for updated PreparedQuery and SelectionCriteria

classDiagram
    class QueryPreparer {
        +prepareQuery(Session, Statement): PreparedQuery
    }
    class PreparedQuery {
        -Statement statement
        -List<Expression> parameters
        -Optional<String> prepareSql
        -boolean isExecuteImmediate
        +getStatement()
        +getParameters()
        +getPrepareSql()
        +isExecuteImmediate()
    }
    class DispatchManager {
        -createQueryInternal(...)
    }
    class SelectionCriteria {
        -boolean authenticated
        -String user
        -Optional<String> source
        -Set<String> clientTags
        -ResourceEstimates resourceEstimates
        -Optional<String> queryType
        -boolean isExecuteImmediate
        +isExecuteImmediate()
    }
    QueryPreparer --> PreparedQuery
    DispatchManager --> SelectionCriteria
    PreparedQuery --> SelectionCriteria: isExecuteImmediate
Loading

Class diagram for SelectorSpec, SelectorRecord, and StaticSelector with isExecuteImmediate

classDiagram
    class SelectorSpec {
        -Optional<Boolean> isExecuteImmediate
        +isExecuteImmediate()
    }
    class SelectorRecord {
        -Optional<Boolean> isExecuteImmediate
        +isExecuteImmediate()
    }
    class StaticSelector {
        -Optional<Boolean> isExecuteImmediate
    }
    SelectorSpec <|-- SelectorRecord
    SelectorSpec <|-- StaticSelector
    StaticSelector --> SelectorSpec: isExecuteImmediate
    SelectorRecord --> SelectorSpec: isExecuteImmediate
Loading

File-Level Changes

Change Details Files
Propagate isExecuteImmediate from ExecuteImmediate statements
  • Detect ExecuteImmediate in QueryPreparer.prepareQuery and set flag
  • Add isExecuteImmediate field to PreparedQuery with constructors and getter
core/trino-main/src/main/java/io/trino/execution/QueryPreparer.java
Carry isExecuteImmediate through dispatch and criteria
  • Add boolean isExecuteImmediate field to SelectionCriteria
  • Pass preparedQuery.isExecuteImmediate() to DispatchManager.createQueryInternal
core/trino-spi/src/main/java/io/trino/spi/resourcegroups/SelectionCriteria.java
core/trino-main/src/main/java/io/trino/dispatcher/DispatchManager.java
Extend selector spec, record, DAO and schema for the new flag
  • Add Optional<Boolean> isExecuteImmediate to SelectorSpec and JSON mapping
  • Include is_execute_immediate column in selectors table and DAO queries
  • Add isExecuteImmediate to SelectorRecord and its row mapper
plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/SelectorSpec.java
plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/SelectorRecord.java
plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/ResourceGroupsDao.java
Enforce matching on isExecuteImmediate in selectors and managers
  • In StaticSelector, add a matcher for the flag
  • Propagate flag to selector builders in AbstractResourceConfigurationManager and DbResourceGroupConfigurationManager
plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/StaticSelector.java
plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/AbstractResourceConfigurationManager.java
plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/DbResourceGroupConfigurationManager.java
Update tests and documentation for the new flag
  • Augment numerous unit tests to pass and assert the default/true values
  • Extend Sphinx docs to describe isExecuteImmediate selector field
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/TestStaticSelector.java
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/TestResourceGroupIdTemplate.java
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/TestFileResourceGroupConfigurationManager.java
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/db/TestResourceGroupsDao.java
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/db/TestDbResourceGroupConfigurationManager.java
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/db/TestDbSourceExactMatchSelector.java
plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/TestingResourceGroups.java
docs/src/main/sphinx/admin/resource-groups.md

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

@github-actions github-actions bot added the docs label Oct 23, 2025
Copy link

@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> `plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/ResourceGroupsDao.java:84` </location>
<code_context>
             "  query_type VARCHAR(512),\n" +
             "  client_tags VARCHAR(512),\n" +
             "  selector_resource_estimate VARCHAR(1024),\n" +
+            "  is_execute_immediate VARCHAR(6),\n" +
             "  FOREIGN KEY (resource_group_id) REFERENCES resource_groups (resource_group_id)\n" +
             ")")
</code_context>

<issue_to_address>
**suggestion:** Consider using a more appropriate type for is_execute_immediate column.

Using VARCHAR for boolean values can cause confusion and compromise data integrity. Prefer BOOLEAN or a constrained CHAR(1) if available for better validation.

Suggested implementation:

```java
            "  is_execute_immediate BOOLEAN,\n" +

```

If there are any places in your codebase where you insert or query the `is_execute_immediate` column, ensure that you use boolean values (`true`/`false`) instead of strings. You may also need to update any related model classes or SQL queries to expect a boolean type.
</issue_to_address>

### Comment 2
<location> `plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/TestStaticSelector.java:224-225` </location>
<code_context>
         assertThat(selector.match(newSelectionCriteria("A.user", "a source b", ImmutableSet.of("tag1", "tag2", "tag3"), EMPTY_RESOURCE_ESTIMATES)).map(SelectionContext::getResourceGroupId)).isEqualTo(Optional.of(resourceGroupId));
     }

+    @Test
+    public void testIsExecuteImmediate()
+    {
+        ResourceGroupId resourceGroupId = new ResourceGroupId(new ResourceGroupId("global"), "foo");
</code_context>

<issue_to_address>
**suggestion (testing):** Missing negative and edge case tests for isExecuteImmediate selector.

Please add tests for cases where isExecuteImmediate is false, unset, or does not match, to fully validate selector behavior.
</issue_to_address>

### Comment 3
<location> `plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/db/TestDbSourceExactMatchSelector.java:56` </location>
<code_context>
+        assertThat(selector.match(new SelectionCriteria(true, "testuser", ImmutableSet.of(), "testuser", Optional.empty(), Optional.of("@test@test_pipeline"), ImmutableSet.of("tag"), EMPTY_RESOURCE_ESTIMATES, Optional.empty(), false))).isEqualTo(Optional.empty());
</code_context>

<issue_to_address>
**suggestion (testing):** No tests for isExecuteImmediate=true in DbSourceExactMatchSelector.

Add tests covering cases where isExecuteImmediate is true to ensure correct selector behavior.
</issue_to_address>

### Comment 4
<location> `plugin/trino-resource-group-managers/src/test/java/io/trino/plugin/resourcegroups/TestResourceGroupIdTemplate.java:51-52` </location>
<code_context>
+        StaticSelector selector = new StaticSelector(Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.of(sourcePattern), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), template);
</code_context>

<issue_to_address>
**suggestion (testing):** No test coverage for isExecuteImmediate in ResourceGroupIdTemplate tests.

Please add tests for isExecuteImmediate in ResourceGroupIdTemplate, focusing on template variable extraction cases.
</issue_to_address>

### Comment 5
<location> `docs/src/main/sphinx/admin/resource-groups.md:209-212` </location>
<code_context>
   client-provided tags associated with the query.

+- `isExecuteImmediate` (optional): Some clients use `EXECUTE IMMEDIATE ...`
+  to run quick queries directly. Use `true` when this selector should match a
+  `EXECUTE IMMEDIATE '...'` query. Use `false` to match all other 
+  queries, omit to match any.
+
</code_context>

<issue_to_address>
**suggestion (typo):** Change 'a EXECUTE IMMEDIATE' to 'an EXECUTE IMMEDIATE' for grammatical correctness.

Use 'an EXECUTE IMMEDIATE ... query' for correct grammar.

```suggestion
- `isExecuteImmediate` (optional): Some clients use `EXECUTE IMMEDIATE ...`
  to run quick queries directly. Use `true` when this selector should match an
  `EXECUTE IMMEDIATE ...` query. Use `false` to match all other 
  queries, omit to match any.
```
</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.

Comment on lines +51 to +52
StaticSelector selector = new StaticSelector(Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.of(sourcePattern), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), template);
SelectionCriteria context = new SelectionCriteria(true, "user", ImmutableSet.of(), "user", Optional.empty(), Optional.of("scheduler.important.testpipeline[5]"), ImmutableSet.of(), EMPTY_RESOURCE_ESTIMATES, Optional.empty(), false);
Copy link

Choose a reason for hiding this comment

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

suggestion (testing): No test coverage for isExecuteImmediate in ResourceGroupIdTemplate tests.

Please add tests for isExecuteImmediate in ResourceGroupIdTemplate, focusing on template variable extraction cases.

Comment on lines +209 to +212
- `isExecuteImmediate` (optional): Some clients use `EXECUTE IMMEDIATE ...`
to run quick queries directly. Use `true` when this selector should match a
`EXECUTE IMMEDIATE '...'` query. Use `false` to match all other
queries, omit to match any.
Copy link

Choose a reason for hiding this comment

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

suggestion (typo): Change 'a EXECUTE IMMEDIATE' to 'an EXECUTE IMMEDIATE' for grammatical correctness.

Use 'an EXECUTE IMMEDIATE ... query' for correct grammar.

Suggested change
- `isExecuteImmediate` (optional): Some clients use `EXECUTE IMMEDIATE ...`
to run quick queries directly. Use `true` when this selector should match a
`EXECUTE IMMEDIATE '...'` query. Use `false` to match all other
queries, omit to match any.
- `isExecuteImmediate` (optional): Some clients use `EXECUTE IMMEDIATE ...`
to run quick queries directly. Use `true` when this selector should match an
`EXECUTE IMMEDIATE ...` query. Use `false` to match all other
queries, omit to match any.

@gertjanal gertjanal changed the title Added isExecuteImmediate selector to resource groups selectors Added isExecuteImmediate selector to resource groups Oct 23, 2025
@gertjanal gertjanal requested a review from xkrogen October 23, 2025 20:03
@xkrogen
Copy link
Member

xkrogen commented Oct 23, 2025

I feel that this may be understanding the use case of EXECUTE IMMEDIATE. The purpose of EXECUTE IMMEDIATE, as far as I am aware, is to make it possible to run parameterized queries in a single statement, rather than needing to explicitly PREPARE/EXECUTE/DEALLOCATE. The IMMEDIATE has nothing to do with how "quickly" the query should be run, so should not be used as a hint for scheduling/resource allocation decisions.

cc our language expert @martint in case I am misunderstanding anything about the intended semantics

@sajjoseph
Copy link
Contributor

I concur with @xkrogen above.
That being said, what this PR does can be repurposed as another great feature. If we can generate resource group selectors based on query text, the original intend can be achieved. For example, SELECT 1 can be marked as a quick query using a regular expression based selector and route to a resource group that gets immediate attention.

Starburst has implemented this feature I believe - https://docs.starburst.io/latest/admin/resource-groups.html#selector-rules

queryText (optional): regex to match against the SQL query string.

  "rootGroups": [
    {
      "name": "global",
      "subGroups": [
        {
          "name": "customer1"
        },
        {
          "name": "customer2"
        }
      ]
    }
  ],
  "selectors": [
    {
      "queryText" : "(?i).*from customer.*",
      "group": "global.customer2"
    },
    {
      "queryText" : "(?i).*from customer.*",
      "group": "global.customer1"
    }
  ]
}```

@wendigo
Copy link
Contributor

wendigo commented Oct 24, 2025

@xkrogen you are correct. There is no reason to treat it differently from any other query. That said, this change isn't something we want to accept and merge.

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

Development

Successfully merging this pull request may close these issues.

4 participants