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

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


The following commit(s) were added to refs/heads/master by this push:
     new 541ed1c26637 feat(trino): track trinodb/trino master via a pinned SHA 
(#19642)
541ed1c26637 is described below

commit 541ed1c266372928ca40d13d6f011cc1f4e639aa
Author: voonhous <[email protected]>
AuthorDate: Mon Aug 17 21:02:18 2026 +0800

    feat(trino): track trinodb/trino master via a pinned SHA (#19642)
    
    * feat(trino): track trinodb/trino master via a pinned SHA (#19640)
    
    hudi-trino stops pinning released Trino 481 and compiles against 
trinodb/trino
    master at the commit in the new trino.sha root pom property (484-SNAPSHOT at
    5b82ec9e7116). Trino publishes no SNAPSHOT artifacts, so scripts/trino/
    bootstrap_trino.sh builds the needed modules from source into the local m2;
    CI restores them from an actions cache keyed on the sha, and the nightly 
compat
    job now pre-seeds that cache and proposes pin advances via a bot/trino-pin 
PR
    (human-merged) instead of only alarming on drift (#19379).
    
    SPI fixups 481 -> pin: split SPI rewrite (ConnectorSplitBatch removed,
    getNextBatch(int, DynamicFilterSnapshot), getSplits with Set<ColumnHandle>,
    wait timeout via getRequestedDynamicFilterWaitTimeoutMillis), 
createPageSource
    gains Optional<ConnectorTableCredentials>, TypeSignature -> TypeDescriptor,
    CacheKeyProvider returns CacheKey, jts-core is now SPI surface (provided in
    module and shim), Hive3MinioDataLake -> Hive3FlociDataLake/Floci in tests,
    dead HudiSplit.getSplitInfo removed.
    
    E2E keeps the released server image (new trino.e2e.version property, also
    feeding trino-jdbc) and auto-skips when the pin has SPI-relevant drift from 
it;
    the shim plugin dir is now unzipped from the packaging zip 
(trino-maven-plugin
    24 emits only the zip). Release branches pin back to a released Trino; the
    release guide gains the pin-back steps.
    
    * test(trino): adapt cache tests to the blob-cache SPI at the pin (#19640)
    
    The pin's blob-cache migration moved cache managers out of catalog
    properties: fs.cache.directories/max-sizes no longer exist as catalog
    config, caches come from host-loaded managers, and the cache span is
    BlobCache.get instead of FileSystemCache.cacheInput.
    
    - HudiQueryRunner loads the memory blob cache manager unconditionally,
      mirroring IcebergQueryRunner; the alluxio tests register the alluxio
      manager via withBlobCache + AlluxioBlobCachePlugin (TestHudiSmokeTest
      grows a getBlobCacheProperties hook for the caching smoke subclass).
    - TestHudiMemoryCacheFileOperations expects BlobCache.get and its span
      filter includes BlobCache.* spans.
    - TestTupleDomainUtilsTest wraps varchar values in Slices.utf8Slice:
      TypeUtils.writeNativeValue no longer coerces raw Strings (482).
    - New test deps trino-blob-cache-memory/-alluxio (BOM-managed); added
      to the bootstrap module list; trino-m2 cache key bumped to v2 since
      the cached artifact set changed.
    
    All five affected test classes pass locally (95 tests) on JDK 25
    against the pinned 484-SNAPSHOT artifacts.
    
    * review(19642): address round-1 review
    
    - hudi_trino_compat.yml: split into a read-only build job (runs mvnw from 
the
      trino checkout with contents: read) and a propose-pin-advance job that 
holds
      the only push credential and runs no third-party code; drop the bot
      gh pr create (GITHUB_TOKEN PRs start no workflow runs, so required checks
      would never report) in favor of pushing bot/trino-pin plus a step-summary
      one-liner for a committer; title type becomes chore(trino); the pin 
advance
      now also refreshes trino.e2e.version from the latest released tag.
    - hudi_trino_e2e.yml: drift gate switched from the compare API (300-file 
cap,
      saturated by a single release cycle) to uncapped per-path commit queries;
      scripts/trino/** added to both paths lists.
    - release_guide.md: pin-back moved to Cut a release branch, before the 
source
      tarball is generated (the voted RC must not ship a -SNAPSHOT trino pin);
      added an SPI-surface scope re-check (jts-core/482) to the pin-back steps.
    - hudi-trino/README.md: fast-iteration loop fixed (version read + unzip 
moved
      into step 3, which the loop repeats); pin ownership/cadence documented.
    - TestHudiSmokeTest: new testDynamicFilterEliminatesAllSplits covering the
      isNone() -> finished early-termination in the rewritten HudiSplitSource.
    - Root pom: pin comment names the nightly job as the e2e-version owner.
    
    * review(19642): address round-2 review
    
    - HudiSplitSource.isFinished now reports unfinished while trinoException is
      pending: the failure callback finishes the queue, and claiming finished at
      that point let the engine stop polling and end the scan silently instead 
of
      surfacing the split-loading failure on the next getNextBatch.
    - testDynamicFilterEliminatesAllSplits now pins probe-side 'Input: 0 rows' 
via
      EXPLAIN ANALYZE; the bare empty-result assert also passed when the filter
      never engaged and the join simply discarded every row.
    - e2e drift gate: lib/trino-filesystem dropped (ships inside the plugin dir,
      cannot skew the boot); the gate keys on the two boundary-crossing 
surfaces,
      core/trino-spi and the HdfsFileSystemLoader contract 
(trino-filesystem-manager
      + the server image's hdfs jar set). API responses are assigned to a 
variable
      before iterating so a transient gh error aborts the step instead of 
reading
      error JSON as drift.
    - build_image.sh derives its default server version from the root pom's
      trino.e2e.version (the literal default would rot when the bot bumps the 
pom).
    - hudi_trino_compat.yml gains a trino_ref dispatch input so the release
      pin-back can verify and pin the released tag exactly; the guide's step 3
      claim now matches what the workflow does.
    
    * review(19642): address round-3 review
    
    - HudiBackgroundSplitLoader's whenAllComplete combiner surfaces generator
      failures before finishing the queue: Guava does not order the per-future
      exception callbacks against the combiner, so a failure in the last future
      could finish the queue before trinoException was set and isFinished would
      answer true with no pending exception.
    - New TestHudiSplitSource unit tests (via a package-private constructor seam
      that keeps the production error-listener wiring): NONE snapshot terminates
      the source with undrained splits, a loader failure blocks isFinished and
      surfaces on the next batch, and normal completion still finishes.
    - e2e drift gate: lib/trino-filesystem restored and lib/trino-memory-context
      added -- HdfsClassLoader delegates exactly those packages from the 
server's
      hdfs jars back to the plugin's bundled copies, so bundling is why they 
cross
      the boundary; comment rewritten accordingly. Read-pin steps in ci and e2e
      fail loudly on an empty sed result (an empty sha would query the default
      branch and skip the suite green).
    - All three trino-m2 cache keys gain the bootstrap-script hash so a 
module-list
      change invalidates caches without a pin move.
    - compat job now also runs the hudi-trino test suite against trino HEAD
      (test-source and behavioral drift blocked pin advances invisibly before);
      drift-issue handler covers test failures; JDK 17 leg installs the two 
extra
      client modules the tests need.
    - release guide no longer asks for a build_image.sh literal edit (the script
      reads trino.e2e.version from the root pom since the round-2 fix).
    
    * review(19642): sync guide pin-back paths with the e2e drift gate
---
 .github/workflows/hudi_trino_ci.yml                |  47 ++++--
 .github/workflows/hudi_trino_compat.yml            | 125 +++++++++++++--
 .github/workflows/hudi_trino_e2e.yml               | 137 +++++++++++++++--
 docker/README.md                                   |  11 +-
 ...r-compose_hadoop340_hive2310_spark402_amd64.yml |   2 +-
 ...r-compose_hadoop340_hive2310_spark402_arm64.yml |   2 +-
 docker/trino/Dockerfile                            |   2 +-
 docker/trino/build_image.sh                        |  26 ++--
 docker/trino/etc/jvm.config                        |   2 +-
 docker/trino/shim/pom.xml                          |  18 ++-
 hudi-trino/README.md                               |  40 +++--
 hudi-trino/pom.xml                                 |  18 +++
 .../trino/plugin/hudi/HudiPageSourceProvider.java  |   3 +
 .../main/java/io/trino/plugin/hudi/HudiSplit.java  |  11 --
 .../io/trino/plugin/hudi/HudiSplitManager.java     |   6 +-
 .../java/io/trino/plugin/hudi/HudiSplitSource.java | 155 ++++++++++---------
 .../plugin/hudi/cache/HudiCacheKeyProvider.java    |   8 +-
 .../hudi/split/HudiBackgroundSplitLoader.java      |  14 ++
 .../trino/plugin/hudi/util/HudiAvroSerializer.java |   2 +-
 .../java/io/trino/plugin/hudi/HudiQueryRunner.java |  37 ++---
 .../hudi/TestHudiAlluxioCacheFileOperations.java   |   8 +-
 .../hudi/TestHudiAlluxioCachingSmokeTest.java      |  11 +-
 ...t.java => TestHudiFlociConnectorSmokeTest.java} |  11 +-
 .../hudi/TestHudiMemoryCacheFileOperations.java    |  10 +-
 .../io/trino/plugin/hudi/TestHudiSmokeTest.java    |  51 ++++++-
 .../io/trino/plugin/hudi/TestHudiSplitSource.java  | 121 +++++++++++++++
 .../plugin/hudi/util/TestTupleDomainUtilsTest.java |   2 +-
 pom.xml                                            |  11 +-
 release/release_guide.md                           |  27 ++++
 rfc/rfc-105/rfc-105.md                             |   4 +-
 scripts/trino/bootstrap_trino.sh                   | 170 +++++++++++++++++++++
 31 files changed, 892 insertions(+), 200 deletions(-)

diff --git a/.github/workflows/hudi_trino_ci.yml 
b/.github/workflows/hudi_trino_ci.yml
index 4dad4f1a3cba..dde37ec8a986 100644
--- a/.github/workflows/hudi_trino_ci.yml
+++ b/.github/workflows/hudi_trino_ci.yml
@@ -8,6 +8,7 @@ on:
     paths:
       - 'hudi-trino/**'
       - '.github/workflows/hudi_trino_ci.yml'
+      - 'scripts/trino/**'
       # Upstream modules the connector build installs (the -am closure of the 
JDK 17
       # install step) plus the poms that own trino.version and the dependency 
pins.
       # Keep in sync with the case patterns in detect-trino-changes below.
@@ -77,6 +78,7 @@ jobs:
             case "$f" in
               hudi-trino/*) TRINO=true ;;
               .github/workflows/hudi_trino_ci.yml) TRINO=true ;;
+              scripts/trino/*) TRINO=true ;;
               # Upstream modules the connector build installs (the -am closure 
of the JDK 17
               # install step) plus the poms that own trino.version and the 
dependency pins.
               # Keep in sync with the push paths above.
@@ -105,6 +107,21 @@ jobs:
       - name: Checkout repository
         if: needs.changes.outputs.trino == 'true'
         uses: actions/checkout@v5
+      - name: Read Trino pin
+        id: trino-pin
+        if: needs.changes.outputs.trino == 'true'
+        run: |
+          set -euo pipefail
+          TRINO_SHA=$(sed -n 's|.*<trino.sha>\(.*\)</trino.sha>.*|\1|p' 
pom.xml)
+          TRINO_VERSION=$(sed -n 
's|.*<trino.version>\(.*\)</trino.version>.*|\1|p' pom.xml)
+          # sed -n ...p exits 0 on no match; an empty value would 
checkout/cache garbage.
+          if [ -z "$TRINO_SHA" ] || [ -z "$TRINO_VERSION" ]; then
+            echo "ERROR: could not read trino.sha/trino.version from pom.xml" 
>&2
+            exit 1
+          fi
+          echo "Pinned trinodb/trino $TRINO_VERSION at $TRINO_SHA"
+          echo "trino_sha=$TRINO_SHA" >> "$GITHUB_OUTPUT"
+          echo "trino_version=$TRINO_VERSION" >> "$GITHUB_OUTPUT"
       # Hudi targets Java 11 and uses Lombok 1.18.36, which does not run on 
JDK 25.
       # Build the upstream modules hudi-trino depends on under JDK 17 first,
       # install them into the local m2, then build the connector itself under 
JDK 25.
@@ -127,20 +144,32 @@ jobs:
           java-version: '25'
           distribution: 'temurin'
           cache: maven
-      # Trino does not publish trino-spi / trino-filesystem / trino-hive 
test-jars to
-      # Maven Central. Check out the matching release tag and install just the 
modules
-      # whose test classifiers we need into the local m2.
-      - name: Checkout trinodb/trino at 481
+      - name: Purge Trino artifacts from the local m2
         if: needs.changes.outputs.trino == 'true'
+        # Artifacts an older pin left behind carry the same SNAPSHOT 
coordinates as the current ones.
+        run: rm -rf ~/.m2/repository/io/trino
+      # Trino publishes neither SNAPSHOT artifacts nor the trino-spi / 
trino-filesystem /
+      # trino-hive / trino-main test-jars, so every io.trino dependency is 
built from the
+      # pinned trinodb/trino commit and cached under that commit.
+      - name: Restore Trino artifacts for the pinned commit
+        id: trino-m2
+        if: needs.changes.outputs.trino == 'true'
+        uses: actions/cache@v4
+        with:
+          path: ~/.m2/repository/io/trino
+          key: trino-m2-v2-${{ hashFiles('scripts/trino/bootstrap_trino.sh') 
}}-${{ steps.trino-pin.outputs.trino_sha }}
+          # No restore-keys on purpose: a partial restore from another pin 
collides on the
+          # same SNAPSHOT coordinates and poisons the build.
+      - name: Checkout trinodb/trino at the pinned commit
+        if: needs.changes.outputs.trino == 'true' && 
steps.trino-m2.outputs.cache-hit != 'true'
         uses: actions/checkout@v5
         with:
           repository: trinodb/trino
-          ref: '481'
+          ref: ${{ steps.trino-pin.outputs.trino_sha }}
           path: trino-src
-      - name: Install Trino test-jars (JDK 25)
-        if: needs.changes.outputs.trino == 'true'
-        working-directory: trino-src
-        run: mvn $MVN_ARGS install -pl 
:trino-spi,:trino-filesystem,:trino-hive,:trino-main -am -DskipTests 
-Dair.check.skip-all=true
+      - name: Build Trino artifacts from source (JDK 25)
+        if: needs.changes.outputs.trino == 'true' && 
steps.trino-m2.outputs.cache-hit != 'true'
+        run: scripts/trino/bootstrap_trino.sh trino-src --skip-checkout
       - name: Build connector (JDK 25)
         if: needs.changes.outputs.trino == 'true'
         run: mvn $MVN_ARGS -Phudi-trino -pl hudi-trino install 
-Dmaven.test.skip=true
diff --git a/.github/workflows/hudi_trino_compat.yml 
b/.github/workflows/hudi_trino_compat.yml
index 701f72115510..eced07275dd5 100644
--- a/.github/workflows/hudi_trino_compat.yml
+++ b/.github/workflows/hudi_trino_compat.yml
@@ -4,11 +4,20 @@ on:
   schedule:
     - cron: '17 4 * * *'
   workflow_dispatch:
+    inputs:
+      trino_ref:
+        description: 'trinodb/trino ref to verify and pin (default: master 
HEAD); the release pin-back dispatches this with the released tag'
+        required: false
+        default: 'master'
 
-# The failure handler files/updates a drift report issue.
+# Two jobs on purpose: the build job executes mvnw from a fresh trinodb/trino 
master
+# checkout, so it must never hold a push-capable token; the propose job holds
+# contents: write but runs no third-party code. The failure handler 
files/updates a
+# drift report issue; on success the propose job pushes the pin-advance branch 
and a
+# human opens the PR (a GITHUB_TOKEN-created PR would start no workflow runs, 
so the
+# required checks could never report).
 permissions:
   contents: read
-  issues: write
 
 env:
   MVN_ARGS: -e -ntp -B -V -Dgpg.skip -Djacoco.skip
@@ -17,17 +26,31 @@ jobs:
   compile-against-trino-master:
     name: Compile hudi-trino against trinodb/trino master
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      issues: write
+    outputs:
+      head_sha: ${{ steps.trino-head.outputs.head_sha }}
+      trino_version: ${{ steps.trino-version.outputs.trino_version }}
     steps:
       - name: Checkout Hudi
         uses: actions/checkout@v5
         with:
           path: hudi
-      - name: Checkout trinodb/trino master
+      - name: Checkout trinodb/trino
         uses: actions/checkout@v5
         with:
           repository: trinodb/trino
-          ref: master
+          # Scheduled runs track master; a manual dispatch may pin any ref, 
e.g. a release tag
+          ref: ${{ inputs.trino_ref || 'master' }}
           path: trino
+      - name: Read trinodb/trino HEAD
+        id: trino-head
+        run: |
+          set -euo pipefail
+          HEAD_SHA=$(git -C trino rev-parse HEAD)
+          echo "trinodb/trino master is at $HEAD_SHA"
+          echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
       # Hudi targets Java 11 and uses Lombok 1.18.36, which does not run on 
JDK 25.
       # Install the upstream Hudi modules under JDK 17 first, then compile the 
connector
       # under JDK 25.
@@ -39,7 +62,9 @@ jobs:
           cache: maven
       - name: Install upstream Hudi modules (JDK 17)
         working-directory: hudi
-        run: mvn $MVN_ARGS install -pl 
:hudi-common,:hudi-hive-sync,:hudi-io,:hudi-sync-common -am 
-Dmaven.test.skip=true -Drat.skip -Dcheckstyle.skip
+        # hudi-client-common and hudi-java-client are needed by the test step's
+        # hudi-trino-tests profile, same as in hudi_trino_ci.yml.
+        run: mvn $MVN_ARGS install -pl 
:hudi-common,:hudi-hive-sync,:hudi-io,:hudi-sync-common,:hudi-client-common,:hudi-java-client
 -am -Dmaven.test.skip=true -Drat.skip -Dcheckstyle.skip
       - name: Set up JDK 25
         uses: actions/setup-java@v5
         with:
@@ -59,11 +84,12 @@ jobs:
           echo "trino_version=$VERSION" >> "$GITHUB_OUTPUT"
           echo "Detected Trino version: $VERSION"
       - name: Install Trino modules from master (JDK 25)
-        working-directory: trino
-        # hudi-trino compiles against these plus their transitive modules 
(spi, cache, metastore,
-        # hive-formats, memory-context). They must come from the master 
checkout -- resolving from
-        # Maven Central would defeat the point of the drift check.
-        run: mvn $MVN_ARGS install -pl 
:trino-hive,:trino-filesystem-manager,:trino-parquet,:trino-plugin-toolkit -am 
-DskipTests -Dair.check.skip-all=true
+        # Same module set the pinned build uses, so a green compile here is a 
promotable pin. The
+        # script purges ~/.m2/repository/io/trino itself and only warns when 
master's version has
+        # rolled past the pinned trino.version.
+        env:
+          HEAD_SHA: ${{ steps.trino-head.outputs.head_sha }}
+        run: hudi/scripts/trino/bootstrap_trino.sh trino --skip-checkout --ref 
"$HEAD_SHA"
       - name: Compile hudi-trino against current Trino SPI (JDK 25)
         id: compile
         working-directory: hudi
@@ -71,11 +97,28 @@ jobs:
           mvn $MVN_ARGS -Phudi-trino \
             -Dtrino.version=${{ steps.trino-version.outputs.trino_version }} \
             -pl hudi-trino compile
+      - name: Run hudi-trino tests against current Trino SPI (JDK 25)
+        id: test
+        working-directory: hudi
+        # Drift that only breaks test sources or test behavior (deleted test 
containers,
+        # renamed tracing spans) must block the pin advance too, not just 
main-source drift.
+        run: |
+          mvn $MVN_ARGS -Phudi-trino,hudi-trino-tests \
+            -Dtrino.version=${{ steps.trino-version.outputs.trino_version }} \
+            -pl hudi-trino test
+      - name: Save Trino artifacts under the candidate pin
+        # Pre-seeds the gating CI cache, which keys on the sha, so the pin 
advance below does not
+        # make every PR rebuild Trino from source.
+        if: steps.compile.outcome == 'success'
+        uses: actions/cache/save@v4
+        with:
+          path: ~/.m2/repository/io/trino
+          key: trino-m2-v2-${{ 
hashFiles('hudi/scripts/trino/bootstrap_trino.sh') }}-${{ 
steps.trino-head.outputs.head_sha }}
       - name: Open issue on failure
-        # Only a connector compile failure is SPI drift. A bare failure() 
would also file
-        # the issue for a failed checkout or a broken trinodb/trino master 
build, with an
+        # Only a connector compile or test failure is SPI drift. A bare 
failure() would also
+        # file the issue for a failed checkout or a broken trinodb/trino 
master build, with an
         # empty version in the title when the failure is before Read Trino 
version.
-        if: failure() && steps.compile.outcome == 'failure'
+        if: failure() && (steps.compile.outcome == 'failure' || 
steps.test.outcome == 'failure')
         uses: actions/github-script@v7
         with:
           script: |
@@ -103,3 +146,59 @@ jobs:
               title: `hudi-trino SPI drift detected against Trino ${version}`,
               body: `${marker}\nNightly compatibility build failed against 
Trino ${version}. See ${runUrl}.`,
             });
+
+  propose-pin-advance:
+    name: Push pin-advance branch
+    runs-on: ubuntu-latest
+    needs: compile-against-trino-master
+    # The only job with a push credential; it checks out apache/hudi alone and 
runs no
+    # Maven or third-party code. Pin PRs are opened and merged by humans.
+    permissions:
+      contents: write
+    steps:
+      - name: Checkout Hudi
+        uses: actions/checkout@v5
+      - name: Push pin-advance branch
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          HEAD_SHA: ${{ needs.compile-against-trino-master.outputs.head_sha }}
+          TRINO_VERSION: ${{ 
needs.compile-against-trino-master.outputs.trino_version }}
+          BASE_BRANCH: ${{ github.ref_name }}
+        run: |
+          set -euo pipefail
+          PINNED_VERSION=$(sed -n 
's|.*<trino.version>\(.*\)</trino.version>.*|\1|p' pom.xml)
+          git config user.name 'github-actions[bot]'
+          git config user.email 
'41898282+github-actions[bot]@users.noreply.github.com'
+          git checkout -B bot/trino-pin
+          sed -i 
"s|<trino.sha>.*</trino.sha>|<trino.sha>${HEAD_SHA}</trino.sha>|" pom.xml
+          if [ "$TRINO_VERSION" != "$PINNED_VERSION" ]; then
+            # Version rollover: the shim's parent tracks trino.version.
+            sed -i 
"s|<trino.version>.*</trino.version>|<trino.version>${TRINO_VERSION}</trino.version>|"
 pom.xml
+            sed -i "/<parent>/,/<\/parent>/ 
s|<version>.*</version>|<version>${TRINO_VERSION}</version>|" 
docker/trino/shim/pom.xml
+          fi
+          # Keep trino.e2e.version current too; without this it silently stops 
being
+          # "the latest released Trino" at the next upstream release. 
Best-effort: an
+          # API hiccup must not block the pin advance.
+          LATEST_RELEASE=$(gh api repos/trinodb/trino/releases/latest --jq 
.tag_name || true)
+          if printf '%s' "$LATEST_RELEASE" | grep -qE '^[0-9]+$'; then
+            sed -i 
"s|<trino.e2e.version>.*</trino.e2e.version>|<trino.e2e.version>${LATEST_RELEASE}</trino.e2e.version>|"
 pom.xml
+          else
+            echo "Could not determine the latest Trino release 
('${LATEST_RELEASE}'); leaving trino.e2e.version unchanged."
+          fi
+          if git diff --quiet; then
+            echo "Pin is already at ${HEAD_SHA}; nothing to propose."
+            exit 0
+          fi
+          TITLE="chore(trino): advance trino master pin to ${HEAD_SHA:0:12}"
+          git commit -am "$TITLE"
+          git push --force origin bot/trino-pin
+          {
+            echo "## Pin advance pushed to bot/trino-pin"
+            echo ""
+            echo "hudi-trino compiles against trinodb/trino ${TRINO_VERSION} 
at ${HEAD_SHA}."
+            echo "Open the PR (bot-created PRs trigger no workflow runs, so a 
human does this):"
+            echo ""
+            echo '```'
+            echo "gh pr create --repo ${GITHUB_REPOSITORY} --base 
${BASE_BRANCH} --head bot/trino-pin --title \"${TITLE}\" --body 
\"Nightly-verified pin advance; see the Hudi Trino SPI Compatibility run.\""
+            echo '```'
+          } >> "$GITHUB_STEP_SUMMARY"
diff --git a/.github/workflows/hudi_trino_e2e.yml 
b/.github/workflows/hudi_trino_e2e.yml
index df2f945e36d3..e6269c94bd47 100644
--- a/.github/workflows/hudi_trino_e2e.yml
+++ b/.github/workflows/hudi_trino_e2e.yml
@@ -16,9 +16,9 @@ on:
       #                         which compiles the whole module, so a break
       #                         anywhere in it fails this pipeline -- not just
       #                         under integ2/.
-      #   pom.xml               owns trino.version, which the shim pom's 
parent,
-      #                         the Dockerfile TRINO_VERSION arg and the
-      #                         hardcoded 481 paths below all track by hand.
+      #   pom.xml               owns trino.version / trino.sha / 
trino.e2e.version:
+      #                         the shim pom's parent, the plugin dir path and 
the
+      #                         server image version below are all derived 
from them.
       - 'hudi-trino/**'
       - 'docker/trino/**'
       - 'docker/compose/docker-compose_hadoop340_hive2310_spark402*'
@@ -27,6 +27,7 @@ on:
       - 'hudi-integ-test/**'
       - 'pom.xml'
       - '.github/workflows/hudi_trino_e2e.yml'
+      - 'scripts/trino/**'
   pull_request:
     branches:
       - master
@@ -41,6 +42,7 @@ on:
       - 'hudi-integ-test/**'
       - 'pom.xml'
       - '.github/workflows/hudi_trino_e2e.yml'
+      - 'scripts/trino/**'
   workflow_dispatch:
 
 concurrency:
@@ -62,12 +64,81 @@ jobs:
     # hudi-trino at HEAD, assembles the plugin dir via the in-repo shim
     # (docker/trino/shim, standing in for the not-yet-released upstream
     # trinodb/trino plugin/trino-hudi shim), bakes it into a local
-    # apachehudi/hudi-trino_481 image, and runs ITTestTrino* against the
-    # spark402 compose stack (the only pair with the trinocoordinator service).
+    # apachehudi/hudi-trino-e2e image on top of the released trino.e2e.version
+    # server, and runs ITTestTrino* against the spark402 compose stack (the 
only
+    # pair with the trinocoordinator service).
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v5
+      - name: Read Trino pin
+        id: trino-pin
+        run: |
+          set -euo pipefail
+          TRINO_SHA=$(sed -n 's|.*<trino.sha>\(.*\)</trino.sha>.*|\1|p' 
pom.xml)
+          TRINO_VERSION=$(sed -n 
's|.*<trino.version>\(.*\)</trino.version>.*|\1|p' pom.xml)
+          E2E_VERSION=$(sed -n 
's|.*<trino.e2e.version>\(.*\)</trino.e2e.version>.*|\1|p' pom.xml)
+          # sed -n ...p exits 0 on no match; an empty sha would make the 
commits API answer
+          # for the default branch and silently skip the suite, so fail loudly 
instead.
+          if [ -z "$TRINO_SHA" ] || [ -z "$TRINO_VERSION" ] || [ -z 
"$E2E_VERSION" ]; then
+            echo "ERROR: could not read 
trino.sha/trino.version/trino.e2e.version from pom.xml" >&2
+            exit 1
+          fi
+          echo "Connector builds at $TRINO_VERSION ($TRINO_SHA); server image 
is $E2E_VERSION"
+          echo "trino_sha=$TRINO_SHA" >> "$GITHUB_OUTPUT"
+          echo "trino_version=$TRINO_VERSION" >> "$GITHUB_OUTPUT"
+          echo "e2e_version=$E2E_VERSION" >> "$GITHUB_OUTPUT"
+      - name: SPI drift gate
+        id: spi-drift
+        # The plugin is built at the pin but loaded by the released 
trino.e2e.version server, so
+        # any SPI / filesystem change between the two can make the image 
unbootable. Skip the run
+        # instead of reporting a failure that no connector change caused.
+        env:
+          GH_TOKEN: ${{ github.token }}
+          TRINO_SHA: ${{ steps.trino-pin.outputs.trino_sha }}
+          TRINO_VERSION: ${{ steps.trino-pin.outputs.trino_version }}
+          E2E_VERSION: ${{ steps.trino-pin.outputs.e2e_version }}
+        run: |
+          set -euo pipefail
+          # Per-path commit queries, NOT the compare API: compare caps its 
file list at 300
+          # and a single Trino release cycle already exceeds that, so a capped 
compare would
+          # flag every pin more than a release old as drifted. The commits API 
is uncapped;
+          # any commit reachable from the pin that touched a boundary-crossing 
path after the
+          # released tag's commit date (excluding the tag commit itself) is 
drift. Existence
+          # is enough, so the first page settles it -- truncation cannot yield 
a false pass.
+          # Gated paths are the surfaces where server-built and pin-built 
classes meet:
+          # core/trino-spi (the server provides it to the plugin classloader), 
and the
+          # HdfsFileSystemLoader contract, where bundled 
trino-filesystem-manager loads the
+          # server image's version-matched hdfs jar set (see 
docker/trino/Dockerfile) whose
+          # HdfsClassLoader then delegates the exact packages 
io.trino.filesystem and
+          # io.trino.memory.context back to the plugin's bundled copies -- so 
those two libs
+          # cross the boundary precisely BECAUSE they are bundled.
+          TAG_SHA=$(gh api "repos/trinodb/trino/commits/${E2E_VERSION}" --jq 
.sha)
+          TAG_DATE=$(gh api "repos/trinodb/trino/commits/${E2E_VERSION}" --jq 
.commit.committer.date)
+          DRIFTED=false
+          for p in core/trino-spi lib/trino-filesystem 
lib/trino-filesystem-manager lib/trino-hdfs lib/trino-memory-context; do
+            # Assign before iterating: a failing substitution in the for-list 
would not trip
+            # set -e, and gh api prints the error body to stdout, so a 
transient API error
+            # would otherwise iterate over error JSON and silently skip the 
suite.
+            SHAS=$(gh api 
"repos/trinodb/trino/commits?sha=${TRINO_SHA}&path=${p}&since=${TAG_DATE}" --jq 
'.[].sha')
+            for c in $SHAS; do
+              if [ "$c" != "$TAG_SHA" ]; then
+                echo "Boundary-crossing change under ${p}: ${c}"
+                DRIFTED=true
+              fi
+            done
+          done
+          echo "drifted=$DRIFTED" >> "$GITHUB_OUTPUT"
+          if [ "$DRIFTED" = "true" ]; then
+            {
+              echo "## Trino E2E skipped: SPI drift window"
+              echo ""
+              echo "The connector is built against trinodb/trino 
\`${TRINO_VERSION}\` (\`${TRINO_SHA}\`), while the"
+              echo "e2e server image is released Trino \`${E2E_VERSION}\`. SPI 
/ filesystem paths changed between"
+              echo "the two, so this run is skipped until the pin and the 
released version re-align."
+            } >> "$GITHUB_STEP_SUMMARY"
+          fi
       - name: Free disk space
+        if: steps.spi-drift.outputs.drifted != 'true'
         run: |
           sudo rm -rf /usr/share/dotnet
           sudo rm -rf /usr/local/lib/android
@@ -75,12 +146,14 @@ jobs:
           sudo rm -rf /usr/local/share/boost
           docker system prune --all --force --volumes
       - name: Pre-pull compose images (fails fast if not published)
+        if: steps.spi-drift.outputs.drifted != 'true'
         run: |
           # Surface a missing sparkadhoc image before the long Maven install. 
The
           # remaining stack images are pulled by docker-compose at test time; 
the
           # trino image is built locally below, never pulled.
           docker pull 
apachehudi/hudi-hadoop_3.4.0-hive_2.3.10-sparkadhoc_4.0.2:latest
       - name: Set up JDK 17
+        if: steps.spi-drift.outputs.drifted != 'true'
         uses: actions/setup-java@v5
         with:
           java-version: '17'
@@ -88,24 +161,50 @@ jobs:
           architecture: x64
           cache: maven
       - name: Build and install Hudi artifacts (JDK 17)
+        if: steps.spi-drift.outputs.drifted != 'true'
         # Full reactor: the compose containers mount the workspace and the 
tests
         # use bundles staged by the -Pintegration-tests build (e.g.
         # docker/hoodie/hadoop/hive_base/target/hoodie-spark-bundle.jar).
         run:
           mvn clean install -T 2 $SCALA_PROFILE -Dspark4.0 -Dflink1.20 
-Pintegration-tests -DskipTests=true -Ddocker.compose.skip=true $MVN_ARGS
       - name: Set up JDK 25
+        if: steps.spi-drift.outputs.drifted != 'true'
         uses: actions/setup-java@v5
         with:
           java-version: '25'
           distribution: 'temurin'
           cache: maven
+      - name: Purge Trino artifacts from the local m2
+        if: steps.spi-drift.outputs.drifted != 'true'
+        # Artifacts an older pin left behind carry the same SNAPSHOT 
coordinates as the current ones.
+        run: rm -rf ~/.m2/repository/io/trino
+      # The connector and the shim assembly resolve io.trino from the pinned 
trinodb/trino
+      # commit: Trino publishes no SNAPSHOT artifacts, so nothing here comes 
from Central.
+      - name: Restore Trino artifacts for the pinned commit
+        id: trino-m2
+        if: steps.spi-drift.outputs.drifted != 'true'
+        uses: actions/cache@v4
+        with:
+          path: ~/.m2/repository/io/trino
+          key: trino-m2-v2-${{ hashFiles('scripts/trino/bootstrap_trino.sh') 
}}-${{ steps.trino-pin.outputs.trino_sha }}
+          # No restore-keys on purpose: a partial restore from another pin 
collides on the
+          # same SNAPSHOT coordinates and poisons the build.
+      - name: Checkout trinodb/trino at the pinned commit
+        if: steps.spi-drift.outputs.drifted != 'true' && 
steps.trino-m2.outputs.cache-hit != 'true'
+        uses: actions/checkout@v5
+        with:
+          repository: trinodb/trino
+          ref: ${{ steps.trino-pin.outputs.trino_sha }}
+          path: trino-src
+      - name: Build Trino artifacts from source (JDK 25)
+        if: steps.spi-drift.outputs.drifted != 'true' && 
steps.trino-m2.outputs.cache-hit != 'true'
+        run: scripts/trino/bootstrap_trino.sh trino-src --skip-checkout
       - name: Build hudi-trino connector (JDK 25)
-        # No trinodb/trino checkout needed: the unpublished Trino test-jars sit
-        # behind the off-by-default hudi-trino-tests profile and packaging
-        # resolves entirely from Maven Central.
+        if: steps.spi-drift.outputs.drifted != 'true'
         run:
           mvn $MVN_ARGS -Phudi-trino -pl hudi-trino install 
-Dmaven.test.skip=true
       - name: Assemble trino-hudi plugin dir via in-repo shim (JDK 25)
+        if: steps.spi-drift.outputs.drifted != 'true'
         # package, NOT install: installing would shadow the real
         # io.trino:trino-hudi release coordinates in the local m2 (the shim pom
         # also hard-disables install via maven.install.skip).
@@ -117,20 +216,30 @@ jobs:
           HUDI_VERSION=$(mvn -q -ntp help:evaluate 
-Dexpression=project.version -DforceStdout)
           echo "Building shim against hudi version: $HUDI_VERSION"
           mvn $MVN_ARGS -f docker/trino/shim/pom.xml clean package -DskipTests 
-Ddep.hudi.version="$HUDI_VERSION"
-      - name: Build apachehudi/hudi-trino_481 image
+      - name: Build apachehudi/hudi-trino-e2e image
+        if: steps.spi-drift.outputs.drifted != 'true'
+        # The plugin dir is named after the version it was built at; the 
server underneath is
+        # the released trino.e2e.version.
+        env:
+          TRINO_VERSION: ${{ steps.trino-pin.outputs.trino_version }}
+          E2E_VERSION: ${{ steps.trino-pin.outputs.e2e_version }}
         run: |
-          docker/trino/build_image.sh --plugin-dir 
docker/trino/shim/target/trino-hudi-481
+          PLUGIN_DIR="docker/trino/shim/target/trino-hudi-${TRINO_VERSION}"
+          # trino-maven-plugin 24 emits only the zip; explode it into the 
plugin dir layout.
+          unzip -o -q "${PLUGIN_DIR}.zip" -d docker/trino/shim/target
+          docker/trino/build_image.sh --plugin-dir "$PLUGIN_DIR" 
--trino-version "${E2E_VERSION}"
           # Sanity: the shim must have produced a populated plugin dir with a
           # service descriptor jar, or Trino cannot load the plugin at boot.
-          echo "plugin dir jar count: $(ls 
docker/trino/shim/target/trino-hudi-481 | wc -l)"
-          ls docker/trino/shim/target/trino-hudi-481/*services*.jar
+          echo "plugin dir jar count: $(ls "$PLUGIN_DIR" | wc -l)"
+          ls "$PLUGIN_DIR"/*services*.jar
       - name: Smoke-boot the Trino image standalone
+        if: steps.spi-drift.outputs.drifted != 'true'
         # Catches image-level boot failures (plugin load errors, bad etc/ 
config)
         # ~30 min before the IT step would, with the full boot log on screen.
         # --hostname trinocoordinator makes the baked discovery.uri 
self-resolve.
         run: |
           docker run -d --name trino-smoke --hostname trinocoordinator \
-            apachehudi/hudi-trino_481:latest
+            apachehudi/hudi-trino-e2e:latest
           ok=""
           for i in $(seq 1 18); do
             if [ "$(docker inspect -f '{{.State.Running}}' trino-smoke)" != 
"true" ]; then
@@ -151,6 +260,7 @@ jobs:
           fi
           docker rm -f trino-smoke
       - name: Set up JDK 17 (restore for the IT run)
+        if: steps.spi-drift.outputs.drifted != 'true'
         # setup-java resets JAVA_HOME on each call; hudi-integ-test needs 17.
         uses: actions/setup-java@v5
         with:
@@ -158,6 +268,7 @@ jobs:
           distribution: 'temurin'
           architecture: x64
       - name: Run Trino E2E ITs (JDK 17)
+        if: steps.spi-drift.outputs.drifted != 'true'
         run: |
           # -DskipITs=false overrides the spark4.0 profile's skipITs=true 
default
           # (see root pom.xml). -Dcompose.profiles=trino starts the 
profile-gated
diff --git a/docker/README.md b/docker/README.md
index 8892399fb33f..560d800063e6 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -200,9 +200,10 @@ changes are needed for the current amd64 plus arm64 image 
set in this repository
 ## Trino E2E image - `/trino`
 
 The Trino E2E stack does not use the `hoodie/hadoop` image tree. 
`docker/trino/` builds
-`apachehudi/hudi-trino_<trino-version>` directly on top of the official 
`trinodb/trino`
-image, baking in a locally-assembled native `trino-hudi` plugin directory and 
the E2E
-catalog config (`connector.name=hudi`, metastore at 
`thrift://hivemetastore:9083`).
+`apachehudi/hudi-trino-e2e` directly on top of the official `trinodb/trino` 
image at the
+root pom's `trino.e2e.version`, baking in a locally-assembled native 
`trino-hudi` plugin
+directory and the E2E catalog config (`connector.name=hudi`, metastore at
+`thrift://hivemetastore:9083`).
 
 This image is built locally on demand (also by the `hudi_trino_e2e.yml` CI 
workflow) and
 is NOT published to Docker Hub. The plugin directory comes from the in-repo 
shim project
@@ -214,7 +215,9 @@ at `docker/trino/shim/` (see `hudi-trino/README.md` for the 
full build-and-run f
 # cut_release_branch.sh cannot bump the literal default in its own pom.
 HUDI_VERSION=$(mvn -q -ntp help:evaluate -Dexpression=project.version 
-DforceStdout)
 mvn -f docker/trino/shim/pom.xml clean package -DskipTests 
-Ddep.hudi.version="$HUDI_VERSION"
-docker/trino/build_image.sh --plugin-dir 
docker/trino/shim/target/trino-hudi-481
+TRINO_VERSION=$(sed -n 's|.*<trino.version>\(.*\)</trino.version>.*|\1|p' 
pom.xml)
+unzip -o -q "docker/trino/shim/target/trino-hudi-$TRINO_VERSION.zip" -d 
docker/trino/shim/target  # trino-maven-plugin 24 emits only the zip
+docker/trino/build_image.sh --plugin-dir 
"docker/trino/shim/target/trino-hudi-$TRINO_VERSION"
 ```
 
 The `trinocoordinator` compose service exists only in the
diff --git 
a/docker/compose/docker-compose_hadoop340_hive2310_spark402_amd64.yml 
b/docker/compose/docker-compose_hadoop340_hive2310_spark402_amd64.yml
index adf964e2288b..a15ea8bfcccb 100644
--- a/docker/compose/docker-compose_hadoop340_hive2310_spark402_amd64.yml
+++ b/docker/compose/docker-compose_hadoop340_hive2310_spark402_amd64.yml
@@ -261,7 +261,7 @@ services:
   # docker/trino/empty-overlay (baked-in plugin used); set TRINO_PLUGIN_DIR to 
a
   # locally-built trino-hudi plugin dir to override it at container start.
   trinocoordinator:
-    image: apachehudi/hudi-trino_481:latest
+    image: apachehudi/hudi-trino-e2e:latest
     profiles: ["trino"]
     hostname: trinocoordinator
     container_name: trinocoordinator
diff --git 
a/docker/compose/docker-compose_hadoop340_hive2310_spark402_arm64.yml 
b/docker/compose/docker-compose_hadoop340_hive2310_spark402_arm64.yml
index adf964e2288b..a15ea8bfcccb 100644
--- a/docker/compose/docker-compose_hadoop340_hive2310_spark402_arm64.yml
+++ b/docker/compose/docker-compose_hadoop340_hive2310_spark402_arm64.yml
@@ -261,7 +261,7 @@ services:
   # docker/trino/empty-overlay (baked-in plugin used); set TRINO_PLUGIN_DIR to 
a
   # locally-built trino-hudi plugin dir to override it at container start.
   trinocoordinator:
-    image: apachehudi/hudi-trino_481:latest
+    image: apachehudi/hudi-trino-e2e:latest
     profiles: ["trino"]
     hostname: trinocoordinator
     container_name: trinocoordinator
diff --git a/docker/trino/Dockerfile b/docker/trino/Dockerfile
index 3189368a2283..891a41aa1ec7 100644
--- a/docker/trino/Dockerfile
+++ b/docker/trino/Dockerfile
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-ARG TRINO_VERSION=481
+ARG TRINO_VERSION=483
 FROM trinodb/trino:${TRINO_VERSION}
 
 USER root
diff --git a/docker/trino/build_image.sh b/docker/trino/build_image.sh
index da1cc8fe2ef1..9a2303ff7117 100755
--- a/docker/trino/build_image.sh
+++ b/docker/trino/build_image.sh
@@ -15,21 +15,25 @@
 #  See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Builds the apachehudi/hudi-trino_<version> image with a locally-built
-# trino-hudi plugin baked in. The plugin dir (typically the in-repo shim's
+# Builds the apachehudi/hudi-trino-e2e image with a locally-built trino-hudi
+# plugin baked in. The plugin dir (typically the in-repo shim's
 # docker/trino/shim/target/trino-hudi-<v>, see docker/trino/shim/pom.xml) is
 # staged into the build context at docker/trino/plugin/ (gitignored), then
 # baked into the image.
 # Usage: ./build_image.sh --plugin-dir <path> [--trino-version <v>] 
[--image-tag <t>]
-# Typical: ./build_image.sh --plugin-dir "$(dirname 
"$0")/shim/target/trino-hudi-481"
-# Note: --trino-version must match the shim pom's parent version and the root
-# pom's trino.version property.
+# Typical: ./build_image.sh --plugin-dir "$(dirname 
"$0")/shim/target/trino-hudi-<trino.version>"
+# Note: --trino-version is the released Trino server image to build on top of
+# (the root pom's trino.e2e.version), not the version the plugin was built at.
 
 set -e
 
-# Default values
+# Directory of this script, so the build context and pom lookups are stable 
regardless of cwd
+SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
+
+# Default values. The server version defaults to the root pom's 
trino.e2e.version (the
+# nightly pin-advance job keeps that current; a literal default here would 
rot).
 PLUGIN_DIR=""
-TRINO_VERSION="481"
+TRINO_VERSION=$(sed -n 
's|.*<trino.e2e.version>\(.*\)</trino.e2e.version>.*|\1|p' 
"$SCRIPT_DIR/../../pom.xml")
 IMAGE_TAG="latest"
 
 # Parse command-line arguments
@@ -43,8 +47,10 @@ while [[ "$#" -gt 0 ]]; do
     shift
 done
 
-# Directory of this script, so the build context path is stable regardless of 
cwd
-SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
+if [ -z "$TRINO_VERSION" ]; then
+  echo "Error: could not read trino.e2e.version from the root pom and no 
--trino-version given." >&2
+  exit 1
+fi
 
 # Validate --plugin-dir: required, must exist and be non-empty
 if [ -z "$PLUGIN_DIR" ]; then
@@ -66,7 +72,7 @@ echo "Staging plugin from '$PLUGIN_DIR' into '$STAGE_DIR'"
 rm -rf "$STAGE_DIR"
 cp -r "$PLUGIN_DIR" "$STAGE_DIR"
 
-IMAGE="apachehudi/hudi-trino_${TRINO_VERSION}:${IMAGE_TAG}"
+IMAGE="apachehudi/hudi-trino-e2e:${IMAGE_TAG}"
 echo "Building $IMAGE (TRINO_VERSION=${TRINO_VERSION})"
 docker build --build-arg TRINO_VERSION="${TRINO_VERSION}" -t "$IMAGE" 
"$SCRIPT_DIR"
 
diff --git a/docker/trino/etc/jvm.config b/docker/trino/etc/jvm.config
index b1d8ff3772dc..8a7098469534 100644
--- a/docker/trino/etc/jvm.config
+++ b/docker/trino/etc/jvm.config
@@ -34,5 +34,5 @@
 # Allow loading dynamic agents (used by JOL, referenced by Trino's runtime).
 -XX:+EnableDynamicAgentLoading
 # NOTE: do NOT add -XX:GCLockerRetryAllocationCount here (Hudi's JDK 11/17 CI
-# workaround): the GCLocker was removed in modern JDKs and the 
trinodb/trino:481
+# workaround): the GCLocker was removed in modern JDKs and the trinodb/trino 
server
 # JVM (JDK 25) refuses to start on the unrecognized option.
diff --git a/docker/trino/shim/pom.xml b/docker/trino/shim/pom.xml
index c263b0d43b21..b614a4194f6b 100644
--- a/docker/trino/shim/pom.xml
+++ b/docker/trino/shim/pom.xml
@@ -33,8 +33,9 @@
   installing would shadow the real io.trino:trino-hudi release coordinates in
   the local repository.
 
-  The parent version below must stay in sync with trino.version in the root 
pom,
-  the TRINO_VERSION ARG in docker/trino/Dockerfile, and the compose image tag.
+  The parent version below must stay in sync with trino.version in the root 
pom. On
+  master that version is a -SNAPSHOT and resolves from the local m2 only, so 
run
+  scripts/trino/bootstrap_trino.sh first; on release branches it resolves from 
Central.
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
     <modelVersion>4.0.0</modelVersion>
@@ -42,8 +43,8 @@
     <parent>
         <groupId>io.trino</groupId>
         <artifactId>trino-root</artifactId>
-        <version>481</version>
-        <!-- Resolve the parent from Maven Central, never the file system. -->
+        <version>484-SNAPSHOT</version>
+        <!-- Resolve the parent from the repositories, never the file system. 
-->
         <relativePath />
     </parent>
 
@@ -153,9 +154,10 @@
             <scope>provided</scope>
         </dependency>
 
-        <!-- NOTE: unlike the upstream 482-SNAPSHOT shim, jts-core must NOT be
-             declared provided here: it is not part of the Trino 481 SPI 
surface
-             and SpiDependencyChecker rejects provided scope for it. It ships
-             inside the plugin dir at its transitive scope instead. -->
+        <dependency>
+            <groupId>org.locationtech.jts</groupId>
+            <artifactId>jts-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/hudi-trino/README.md b/hudi-trino/README.md
index 72c848ba2c18..1308a21698b9 100644
--- a/hudi-trino/README.md
+++ b/hudi-trino/README.md
@@ -19,9 +19,21 @@
 
 Hudi connector for Trino (RFC-105). Published as `org.apache.hudi:hudi-trino` 
-- a regular non-shaded JAR. The Trino-side `trino-hudi` plugin module depends 
on this artifact and Trino's URLClassLoader isolates the plugin's transitive 
deps from the rest of the server, so no shading is required.
 
+## Bootstrap Trino (do this first)
+
+On master no `io.trino` artifact resolves from Maven Central: master tracks 
`trinodb/trino` master at the commit pinned by `trino.sha` in the root pom, and 
Trino publishes no SNAPSHOT artifacts. Pin ownership: the nightly `Hudi Trino 
SPI Compatibility` job verifies trino HEAD and pushes a `bot/trino-pin` branch 
(also refreshing `trino.e2e.version`); a committer opens and merges its PR, so 
the pin advances roughly nightly-to-weekly. One time per pin advance, clone 
`trinodb/trino` (or reus [...]
+
+```
+scripts/trino/bootstrap_trino.sh /path/to/trino
+```
+
+Takes roughly 10-30 minutes and installs everything the connector needs, 
including the four test-jars and the `trino-root` pom.
+
+On release branches `trino.version` is a released number, so compile deps 
resolve from Central and bootstrap is only needed for running tests.
+
 ## Build
 
-Excluded from default builds. Activate the `hudi-trino` Maven profile:
+Excluded from default builds. Activate the `hudi-trino` Maven profile (after 
bootstrap):
 
 ```
 # tests need Trino test-jars not on Maven Central (see Running tests); skip 
them in the default build
@@ -32,18 +44,15 @@ Requires JDK 25 (enforced via `maven-enforcer-plugin`).
 
 ## Running tests
 
-Tests depend on Trino test-jars (`trino-spi`, `trino-filesystem`, 
`trino-hive`, `trino-main` at the `tests` classifier). Trino does not publish 
three of those to Maven Central, so the test deps live behind the 
`hudi-trino-tests` profile, off by default.
+Tests depend on Trino test-jars (`trino-spi`, `trino-filesystem`, 
`trino-hive`, `trino-main` at the `tests` classifier). Trino publishes none of 
those, so the test deps live behind the `hudi-trino-tests` profile, off by 
default.
 
-To run the tests:
-
-1. Build the matching Trino version locally so its `*-tests.jar` artifacts 
land in your `~/.m2` (see `trino.version` in the root pom for the version to 
build).
-2. Activate both profiles:
+After bootstrap, activate both profiles:
 
 ```
 mvn -Phudi-trino,hudi-trino-tests -pl hudi-trino test
 ```
 
-CI follows the same two steps: `.github/workflows/hudi_trino_ci.yml` installs 
the test-jars from a source checkout of the pinned Trino tag, then runs with 
both profiles enabled.
+CI follows the same two steps: `.github/workflows/hudi_trino_ci.yml` runs 
`bootstrap_trino.sh` against the pinned commit (cached per `trino.sha`), then 
runs with both profiles enabled.
 
 ## End-to-end tests (docker)
 
@@ -55,7 +64,11 @@ project mirroring the upstream `trinodb/trino` 
`plugin/trino-hudi` shim planned
 RFC-105 (not yet released upstream). CI runs the same flow via
 `.github/workflows/hudi_trino_e2e.yml`.
 
-Local flow:
+The plugin is built at the pinned `trino.version` while the server image is 
the released
+`trino.e2e.version`; CI auto-skips the suite during SPI drift windows (SPI or 
filesystem changes
+between the two).
+
+Local flow (after bootstrap):
 
 ```
 # 1. JDK 17: full reactor incl. the integ-test bundles the containers mount
@@ -69,11 +82,16 @@ mvn -Phudi-trino -pl hudi-trino install 
-Dmaven.test.skip=true
 #    shadow the real io.trino:trino-hudi release coordinates in the local m2).
 #    dep.hudi.version comes from the reactor pom: the shim sits outside the
 #    reactor, so cut_release_branch.sh cannot bump its literal default.
+#    The unzip lives here, not in step 4: the fast-iteration loop below repeats
+#    steps 2-3 only, and `clean` wipes the previously exploded dir.
 HUDI_VERSION=$(mvn -q -ntp help:evaluate -Dexpression=project.version 
-DforceStdout)
+TRINO_VERSION=$(sed -n 's|.*<trino.version>\(.*\)</trino.version>.*|\1|p' 
pom.xml)
 mvn -f docker/trino/shim/pom.xml clean package -DskipTests 
-Ddep.hudi.version="$HUDI_VERSION"
+unzip -o -q "docker/trino/shim/target/trino-hudi-$TRINO_VERSION.zip" -d 
docker/trino/shim/target  # trino-maven-plugin 24 emits only the zip
 
-# 4. Build the Trino image (locally tagged; never published)
-docker/trino/build_image.sh --plugin-dir 
docker/trino/shim/target/trino-hudi-481
+# 4. Build the Trino image (locally tagged; never published). The base server 
defaults to
+#    trino.e2e.version; pass --trino-version to override it.
+docker/trino/build_image.sh --plugin-dir 
"docker/trino/shim/target/trino-hudi-$TRINO_VERSION"
 
 # 5. JDK 17: run the suite (only the spark402 compose pair has the trino 
service)
 mvn verify -pl hudi-integ-test -Dscala-2.13 -Dscala.binary.version=2.13 
-Dspark4.0 \
@@ -83,7 +101,7 @@ mvn verify -pl hudi-integ-test -Dscala-2.13 
-Dscala.binary.version=2.13 -Dspark4
 ```
 
 Fast iteration loop: after changing connector code, redo steps 2-3, then add
-`-Dtrino.plugin.dir=$PWD/docker/trino/shim/target/trino-hudi-481` to step 5. 
The
+`-Dtrino.plugin.dir=$PWD/docker/trino/shim/target/trino-hudi-$TRINO_VERSION` 
to step 5. The
 container's overlay entrypoint swaps the freshly built plugin dir in at start, 
so the
 image rebuild (step 4) is skipped.
 
diff --git a/hudi-trino/pom.xml b/hudi-trino/pom.xml
index 4a488ee7309b..d2454ca91978 100644
--- a/hudi-trino/pom.xml
+++ b/hudi-trino/pom.xml
@@ -391,6 +391,12 @@
             <scope>provided</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.locationtech.jts</groupId>
+            <artifactId>jts-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.openjdk.jol</groupId>
             <artifactId>jol-core</artifactId>
@@ -445,6 +451,18 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>io.trino</groupId>
+            <artifactId>trino-blob-cache-alluxio</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.trino</groupId>
+            <artifactId>trino-blob-cache-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>io.trino</groupId>
             <artifactId>trino-client</artifactId>
diff --git 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiPageSourceProvider.java 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiPageSourceProvider.java
index 2803f8ae231a..1d58eb7adc1c 100644
--- a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiPageSourceProvider.java
+++ b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiPageSourceProvider.java
@@ -45,6 +45,7 @@ import io.trino.spi.connector.ConnectorPageSource;
 import io.trino.spi.connector.ConnectorPageSourceProvider;
 import io.trino.spi.connector.ConnectorSession;
 import io.trino.spi.connector.ConnectorSplit;
+import io.trino.spi.connector.ConnectorTableCredentials;
 import io.trino.spi.connector.ConnectorTableHandle;
 import io.trino.spi.connector.ConnectorTransactionHandle;
 import io.trino.spi.connector.DynamicFilter;
@@ -142,11 +143,13 @@ public class HudiPageSourceProvider
     }
 
     @Override
+    @SuppressWarnings("deprecation")
     public ConnectorPageSource createPageSource(
             ConnectorTransactionHandle transaction,
             ConnectorSession session,
             ConnectorSplit connectorSplit,
             ConnectorTableHandle connectorTable,
+            Optional<ConnectorTableCredentials> tableCredentials,
             List<ColumnHandle> columns,
             DynamicFilter dynamicFilter)
     {
diff --git a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplit.java 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplit.java
index 32f1d32aa3f6..9159ec060ca2 100644
--- a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplit.java
+++ b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplit.java
@@ -17,7 +17,6 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import io.trino.plugin.hive.HiveColumnHandle;
 import io.trino.plugin.hive.HivePartitionKey;
 import io.trino.plugin.hudi.file.HudiBaseFile;
@@ -28,7 +27,6 @@ import io.trino.spi.connector.ConnectorSplit;
 import io.trino.spi.predicate.TupleDomain;
 
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -80,15 +78,6 @@ public class HudiSplit
         this.cachingHostAddresses = requireNonNull(cachingHostAddresses, 
"cachingHostAddresses is null");
     }
 
-    public Map<String, String> getSplitInfo()
-    {
-        return ImmutableMap.<String, String>builder()
-                .put("baseFile", baseFile.toString())
-                .put("logFiles", logFiles.toString())
-                .put("commitTime", commitTime)
-                .buildOrThrow();
-    }
-
     @JsonProperty
     public Optional<HudiBaseFile> getBaseFile()
     {
diff --git 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitManager.java 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitManager.java
index 7084435b8733..df0018a49268 100644
--- a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitManager.java
+++ b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitManager.java
@@ -24,13 +24,13 @@ import 
io.trino.plugin.base.classloader.ClassLoaderSafeConnectorSplitSource;
 import io.trino.plugin.hive.HiveColumnHandle;
 import io.trino.plugin.hive.HiveTransactionHandle;
 import io.trino.spi.TrinoException;
+import io.trino.spi.connector.ColumnHandle;
 import io.trino.spi.connector.ConnectorSession;
 import io.trino.spi.connector.ConnectorSplitManager;
 import io.trino.spi.connector.ConnectorSplitSource;
 import io.trino.spi.connector.ConnectorTableHandle;
 import io.trino.spi.connector.ConnectorTransactionHandle;
 import io.trino.spi.connector.Constraint;
-import io.trino.spi.connector.DynamicFilter;
 import io.trino.spi.connector.TableNotFoundException;
 import io.trino.spi.security.ConnectorIdentity;
 import org.apache.hudi.common.util.HoodieTimer;
@@ -39,6 +39,7 @@ import org.apache.hudi.common.util.Lazy;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.BiFunction;
@@ -77,7 +78,7 @@ public class HudiSplitManager
             ConnectorTransactionHandle transaction,
             ConnectorSession session,
             ConnectorTableHandle tableHandle,
-            DynamicFilter dynamicFilter,
+            Set<ColumnHandle> dynamicFilterColumns,
             Constraint constraint)
     {
         HudiTableHandle hudiTableHandle = (HudiTableHandle) tableHandle;
@@ -98,7 +99,6 @@ public class HudiSplitManager
                 getMaxSplitsPerSecond(session),
                 getMaxOutstandingSplits(session),
                 lazyAllPartitions,
-                dynamicFilter,
                 getDynamicFilteringWaitTimeout(session));
         return new ClassLoaderSafeConnectorSplitSource(splitSource, 
HudiSplitManager.class.getClassLoader());
     }
diff --git a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitSource.java 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitSource.java
index ab6bae93cfc8..a578cc9b73c9 100644
--- a/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitSource.java
+++ b/hudi-trino/src/main/java/io/trino/plugin/hudi/HudiSplitSource.java
@@ -13,7 +13,6 @@
  */
 package io.trino.plugin.hudi;
 
-import com.google.common.base.Stopwatch;
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.Futures;
 import io.airlift.log.Logger;
@@ -34,7 +33,8 @@ import io.trino.spi.TrinoException;
 import io.trino.spi.connector.ConnectorSession;
 import io.trino.spi.connector.ConnectorSplit;
 import io.trino.spi.connector.ConnectorSplitSource;
-import io.trino.spi.connector.DynamicFilter;
+import io.trino.spi.connector.DynamicFilterSnapshot;
+import io.trino.spi.connector.SchemaTableName;
 import io.trino.spi.predicate.Domain;
 import io.trino.spi.predicate.NullableValue;
 import io.trino.spi.predicate.TupleDomain;
@@ -56,7 +56,10 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
@@ -66,22 +69,18 @@ import static 
io.trino.plugin.hudi.HudiSessionProperties.getMinimumAssignedSplit
 import static 
io.trino.plugin.hudi.HudiSessionProperties.getStandardSplitWeightSize;
 import static 
io.trino.plugin.hudi.HudiSessionProperties.isHudiMetadataTableEnabled;
 import static 
io.trino.plugin.hudi.HudiSessionProperties.isSizeBasedSplitWeightsEnabled;
-import static java.util.Objects.requireNonNull;
 import static java.util.concurrent.CompletableFuture.completedFuture;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
 public class HudiSplitSource
         implements ConnectorSplitSource
 {
     private static final Logger log = Logger.get(HudiSplitSource.class);
 
-    private static final ConnectorSplitBatch EMPTY_BATCH = new 
ConnectorSplitBatch(ImmutableList.of(), false);
     private final AsyncQueue<ConnectorSplit> queue;
     private final ScheduledFuture splitLoaderFuture;
     private final AtomicReference<TrinoException> trinoException = new 
AtomicReference<>();
-    private final DynamicFilter dynamicFilter;
+    private final AtomicBoolean finished = new AtomicBoolean();
     private final long dynamicFilteringWaitTimeoutMillis;
-    private final Stopwatch dynamicFilterWaitStopwatch;
 
     public HudiSplitSource(
             ConnectorSession session,
@@ -91,77 +90,85 @@ public class HudiSplitSource
             int maxSplitsPerSecond,
             int maxOutstandingSplits,
             Lazy<Map<String, Partition>> lazyPartitions,
-            DynamicFilter dynamicFilter,
             Duration dynamicFilteringWaitTimeoutMillis)
     {
-        boolean enableMetadataTable = isHudiMetadataTableEnabled(session);
-        Lazy<HoodieTableMetadata> lazyTableMetadata = Lazy.lazily(() -> {
-            HoodieTimer timer = HoodieTimer.start();
-            HoodieMetadataConfig metadataConfig = 
HoodieMetadataConfig.newBuilder()
-                    .enable(enableMetadataTable)
-                    .build();
-            HoodieTableMetaClient metaClient = tableHandle.getMetaClient();
-            HoodieEngineContext engineContext = new 
HoodieLocalEngineContext(metaClient.getStorage().getConf());
-
-            // Defer to the native factory, which creates a 
HoodieBackedTableMetadata when the
-            // metadata table is enabled and initialized, and falls back to 
FileSystemBackedTableMetadata
-            // otherwise.
-            HoodieTableMetadata tableMetadata = 
NativeTableMetadataFactory.getInstance().create(
-                    engineContext, metaClient.getStorage(), metadataConfig, 
metaClient.getBasePath().toString(), true);
-            log.info("Loaded table metadata for table: %s in %s ms", 
tableHandle.getSchemaTableName(), timer.endTimer());
-            return tableMetadata;
-        });
+        this(
+                new ThrottledAsyncQueue<>(maxSplitsPerSecond, 
maxOutstandingSplits, executor),
+                splitLoaderExecutorService,
+                (queue, errorListener) -> {
+                    boolean enableMetadataTable = 
isHudiMetadataTableEnabled(session);
+                    Lazy<HoodieTableMetadata> lazyTableMetadata = 
Lazy.lazily(() -> {
+                        HoodieTimer timer = HoodieTimer.start();
+                        HoodieMetadataConfig metadataConfig = 
HoodieMetadataConfig.newBuilder()
+                                .enable(enableMetadataTable)
+                                .build();
+                        HoodieTableMetaClient metaClient = 
tableHandle.getMetaClient();
+                        HoodieEngineContext engineContext = new 
HoodieLocalEngineContext(metaClient.getStorage().getConf());
+
+                        // Defer to the native factory, which creates a 
HoodieBackedTableMetadata when the
+                        // metadata table is enabled and initialized, and 
falls back to FileSystemBackedTableMetadata
+                        // otherwise.
+                        HoodieTableMetadata tableMetadata = 
NativeTableMetadataFactory.getInstance().create(
+                                engineContext, metaClient.getStorage(), 
metadataConfig, metaClient.getBasePath().toString(), true);
+                        log.info("Loaded table metadata for table: %s in %s 
ms", tableHandle.getSchemaTableName(), timer.endTimer());
+                        return tableMetadata;
+                    });
+
+                    HudiDirectoryLister hudiDirectoryLister = new 
HudiSnapshotDirectoryLister(
+                            session,
+                            tableHandle,
+                            enableMetadataTable,
+                            lazyTableMetadata);
 
-        HudiDirectoryLister hudiDirectoryLister = new 
HudiSnapshotDirectoryLister(
-                session,
-                tableHandle,
-                enableMetadataTable,
-                lazyTableMetadata);
-
-        this.queue = new ThrottledAsyncQueue<>(maxSplitsPerSecond, 
maxOutstandingSplits, executor);
-        HudiBackgroundSplitLoader splitLoader = new HudiBackgroundSplitLoader(
-                session,
-                tableHandle,
-                hudiDirectoryLister,
-                queue,
-                executor,
-                createSplitWeightProvider(session),
-                lazyPartitions,
-                enableMetadataTable,
-                lazyTableMetadata,
-                throwable -> {
-                    trinoException.compareAndSet(null, new 
TrinoException(HUDI_CANNOT_OPEN_SPLIT,
-                            "Failed to generate splits for " + 
tableHandle.getSchemaTableName(), throwable));
-                    queue.finish();
-                });
+                    return new HudiBackgroundSplitLoader(
+                            session,
+                            tableHandle,
+                            hudiDirectoryLister,
+                            queue,
+                            executor,
+                            createSplitWeightProvider(session),
+                            lazyPartitions,
+                            enableMetadataTable,
+                            lazyTableMetadata,
+                            errorListener);
+                },
+                tableHandle.getSchemaTableName(),
+                dynamicFilteringWaitTimeoutMillis);
+    }
+
+    // Visible for tests: lets a test drive the split loader directly while 
keeping the
+    // error-listener wiring (set trinoException, then finish the queue -- 
isFinished
+    // relies on that order) identical to production.
+    HudiSplitSource(
+            AsyncQueue<ConnectorSplit> queue,
+            ScheduledExecutorService splitLoaderExecutorService,
+            BiFunction<AsyncQueue<ConnectorSplit>, Consumer<Throwable>, 
Runnable> splitLoaderFactory,
+            SchemaTableName tableName,
+            Duration dynamicFilteringWaitTimeoutMillis)
+    {
+        this.queue = queue;
+        Runnable splitLoader = splitLoaderFactory.apply(queue, throwable -> {
+            trinoException.compareAndSet(null, new 
TrinoException(HUDI_CANNOT_OPEN_SPLIT,
+                    "Failed to generate splits for " + tableName, throwable));
+            queue.finish();
+        });
         this.splitLoaderFuture = 
splitLoaderExecutorService.schedule(splitLoader, 0, TimeUnit.MILLISECONDS);
-        this.dynamicFilter = requireNonNull(dynamicFilter, "dynamicFilter is 
null");
         this.dynamicFilteringWaitTimeoutMillis = 
dynamicFilteringWaitTimeoutMillis.toMillis();
-        this.dynamicFilterWaitStopwatch = Stopwatch.createStarted();
     }
 
     @Override
-    public CompletableFuture<ConnectorSplitBatch> getNextBatch(int maxSize)
+    public CompletableFuture<List<ConnectorSplit>> getNextBatch(int maxSize, 
DynamicFilterSnapshot dynamicFilterSnapshot)
     {
-        // If dynamic filtering is enabled and we haven't timed out, wait for 
the build side to provide the dynamic filter.
-        long timeLeft = dynamicFilteringWaitTimeoutMillis - 
dynamicFilterWaitStopwatch.elapsed(MILLISECONDS);
-        if (dynamicFilter.isAwaitable() && timeLeft > 0) {
-            // If the filter is not ready, return an empty batch. The query 
engine will call getNextBatch() again.
-            // As long as isFinished() is false, effectively polling until the 
filter is ready or timeout occurs.
-            return dynamicFilter.isBlocked()
-                    .thenApply(_ -> EMPTY_BATCH)
-                    .completeOnTimeout(EMPTY_BATCH, timeLeft, MILLISECONDS);
-        }
-
         TupleDomain<HiveColumnHandle> dynamicFilterPredicate =
-                
dynamicFilter.getCurrentPredicate().transformKeys(HiveColumnHandle.class::cast);
+                
dynamicFilterSnapshot.currentPredicate().transformKeys(HiveColumnHandle.class::cast);
 
         if (dynamicFilterPredicate.isNone()) {
             close();
-            return completedFuture(new ConnectorSplitBatch(ImmutableList.of(), 
true));
+            // The queue may still hold undrained splits, so 
queue.isFinished() would never turn true here
+            finished.set(true);
+            return completedFuture(ImmutableList.of());
         }
 
-        boolean noMoreSplits = isFinished();
         Throwable throwable = trinoException.get();
         if (throwable != null) {
             return CompletableFuture.failedFuture(throwable);
@@ -169,13 +176,9 @@ public class HudiSplitSource
 
         return toCompletableFuture(Futures.transform(
                 queue.getBatchAsync(maxSize),
-                splits ->
-                {
-                    List<ConnectorSplit> filteredSplits = splits.stream()
-                            .filter(split -> 
partitionMatchesPredicate((HudiSplit) split, dynamicFilterPredicate))
-                            .collect(toImmutableList());
-                    return new ConnectorSplitBatch(filteredSplits, 
noMoreSplits);
-                },
+                splits -> splits.stream()
+                        .filter(split -> partitionMatchesPredicate((HudiSplit) 
split, dynamicFilterPredicate))
+                        .collect(toImmutableList()),
                 directExecutor()));
     }
 
@@ -188,7 +191,17 @@ public class HudiSplitSource
     @Override
     public boolean isFinished()
     {
-        return splitLoaderFuture.isDone() && queue.isFinished();
+        // The failure callback sets trinoException before finishing the 
queue, so once the queue
+        // reports finished the exception (if any) is visible here. Claiming 
finished while an
+        // exception is pending would let the engine stop polling and end the 
scan silently;
+        // reporting unfinished instead makes the next getNextBatch surface 
the failure.
+        return finished.get() || (splitLoaderFuture.isDone() && 
queue.isFinished() && trinoException.get() == null);
+    }
+
+    @Override
+    public long getRequestedDynamicFilterWaitTimeoutMillis()
+    {
+        return dynamicFilteringWaitTimeoutMillis;
     }
 
     public static HudiSplitWeightProvider 
createSplitWeightProvider(ConnectorSession session)
diff --git 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/cache/HudiCacheKeyProvider.java 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/cache/HudiCacheKeyProvider.java
index cd07e1ab3f13..0131fa7bbe45 100644
--- 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/cache/HudiCacheKeyProvider.java
+++ 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/cache/HudiCacheKeyProvider.java
@@ -15,6 +15,7 @@ package io.trino.plugin.hudi.cache;
 
 import io.trino.filesystem.TrinoInputFile;
 import io.trino.filesystem.cache.CacheKeyProvider;
+import io.trino.spi.cache.CacheKey;
 
 import java.util.Optional;
 
@@ -22,7 +23,7 @@ public class HudiCacheKeyProvider
         implements CacheKeyProvider
 {
     @Override
-    public Optional<String> getCacheKey(TrinoInputFile inputFile)
+    public Optional<CacheKey> getCacheKey(TrinoInputFile inputFile)
     {
         String path = inputFile.location().path();
         if (path.endsWith(".trinoSchema") || 
path.contains("/.trinoPermissions/")
@@ -32,7 +33,8 @@ public class HudiCacheKeyProvider
             // and Hudi table properties file that can be mutable
             return Optional.empty();
         }
-        // Other Hudi data and metadata files are immutable
-        return Optional.of(path);
+        // Other Hudi data and metadata files are immutable, so the location 
alone identifies the
+        // contents; keying by its components also lets a directory's entries 
be invalidated by prefix
+        return Optional.of(CacheKeyProvider.locationKey(inputFile.location()));
     }
 }
diff --git 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/split/HudiBackgroundSplitLoader.java
 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/split/HudiBackgroundSplitLoader.java
index e33bf772dc1f..ee46dd8fa508 100644
--- 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/split/HudiBackgroundSplitLoader.java
+++ 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/split/HudiBackgroundSplitLoader.java
@@ -54,6 +54,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.function.Consumer;
@@ -166,6 +167,19 @@ public class HudiBackgroundSplitLoader
 
         Futures.whenAllComplete(futures)
                 .run(() -> {
+                    // Guava does not order the per-future exception callbacks 
against this
+                    // combiner, so a failure in the last future could 
otherwise finish the
+                    // queue before the error listener records it and 
HudiSplitSource.isFinished
+                    // would answer true with no pending exception. Surface 
failures here first;
+                    // the listener is idempotent, so double reporting is 
harmless.
+                    for (ListenableFuture<Void> future : futures) {
+                        try {
+                            Futures.getDone(future);
+                        }
+                        catch (ExecutionException e) {
+                            errorListener.accept(e.getCause());
+                        }
+                    }
                     asyncQueue.finish();
                     log.info("Partition pruning split generation finished on 
table %s.%s", tableHandle.getSchemaName(), tableHandle.getTableName());
                 }, directExecutor());
diff --git 
a/hudi-trino/src/main/java/io/trino/plugin/hudi/util/HudiAvroSerializer.java 
b/hudi-trino/src/main/java/io/trino/plugin/hudi/util/HudiAvroSerializer.java
index 8b035c084af6..cb2414ee40d8 100644
--- a/hudi-trino/src/main/java/io/trino/plugin/hudi/util/HudiAvroSerializer.java
+++ b/hudi-trino/src/main/java/io/trino/plugin/hudi/util/HudiAvroSerializer.java
@@ -496,7 +496,7 @@ public class HudiAvroSerializer
             type.writeObject(output, trinoNativeDecimalValue);
         }
         else {
-            throw new TrinoException(GENERIC_INTERNAL_ERROR, "Unhandled type 
for Object: " + type.getTypeSignature());
+            throw new TrinoException(GENERIC_INTERNAL_ERROR, "Unhandled type 
for Object: " + type.getTypeDescriptor());
         }
     }
 
diff --git a/hudi-trino/src/test/java/io/trino/plugin/hudi/HudiQueryRunner.java 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/HudiQueryRunner.java
index e11efbf3a569..2939b87384b0 100644
--- a/hudi-trino/src/test/java/io/trino/plugin/hudi/HudiQueryRunner.java
+++ b/hudi-trino/src/test/java/io/trino/plugin/hudi/HudiQueryRunner.java
@@ -17,11 +17,12 @@ import 
com.google.errorprone.annotations.CanIgnoreReturnValue;
 import io.airlift.log.Level;
 import io.airlift.log.Logger;
 import io.airlift.log.Logging;
+import io.trino.blob.cache.memory.MemoryBlobCachePlugin;
 import io.trino.filesystem.Location;
 import io.trino.metastore.Database;
 import io.trino.metastore.HiveMetastoreFactory;
 import io.trino.plugin.base.util.Closables;
-import io.trino.plugin.hive.containers.Hive3MinioDataLake;
+import io.trino.plugin.hive.containers.Hive3FlociDataLake;
 import io.trino.plugin.hudi.testing.HudiTablesInitializer;
 import io.trino.plugin.hudi.testing.ResourceHudiTablesInitializer;
 import io.trino.plugin.hudi.testing.TpchHudiTablesInitializer;
@@ -35,9 +36,9 @@ import java.util.Map;
 import java.util.Optional;
 
 import static io.trino.testing.TestingSession.testSessionBuilder;
-import static io.trino.testing.containers.Minio.MINIO_ROOT_USER;
-import static io.trino.testing.containers.Minio.MINIO_REGION;
-import static io.trino.testing.containers.Minio.MINIO_ROOT_PASSWORD;
+import static io.trino.testing.containers.Floci.FLOCI_ACCESS_KEY;
+import static io.trino.testing.containers.Floci.FLOCI_REGION;
+import static io.trino.testing.containers.Floci.FLOCI_SECRET_KEY;
 import static java.util.Objects.requireNonNull;
 
 public final class HudiQueryRunner
@@ -56,14 +57,14 @@ public final class HudiQueryRunner
         return new Builder("local:///");
     }
 
-    public static Builder builder(Hive3MinioDataLake hiveMinioDataLake)
+    public static Builder builder(Hive3FlociDataLake hiveFlociDataLake)
     {
-        return new Builder("s3://" + hiveMinioDataLake.getBucketName() + "/")
-                .addConnectorProperty("fs.native-s3.enabled", "true")
-                .addConnectorProperty("s3.aws-access-key", MINIO_ROOT_USER)
-                .addConnectorProperty("s3.aws-secret-key", MINIO_ROOT_PASSWORD)
-                .addConnectorProperty("s3.region", MINIO_REGION)
-                .addConnectorProperty("s3.endpoint", 
hiveMinioDataLake.getMinio().getMinioAddress())
+        return new Builder("s3://" + hiveFlociDataLake.getBucketName() + "/")
+                .addConnectorProperty("fs.s3.enabled", "true")
+                .addConnectorProperty("s3.aws-access-key", FLOCI_ACCESS_KEY)
+                .addConnectorProperty("s3.aws-secret-key", FLOCI_SECRET_KEY)
+                .addConnectorProperty("s3.region", FLOCI_REGION)
+                .addConnectorProperty("s3.endpoint", 
hiveFlociDataLake.floci().endpoint().toString())
                 .addConnectorProperty("s3.path-style-access", "true");
     }
 
@@ -111,6 +112,8 @@ public final class HudiQueryRunner
             DistributedQueryRunner queryRunner = super.build();
             try {
                 queryRunner.installPlugin(new 
TestingHudiPlugin(queryRunner.getCoordinator().getBaseDataDir().resolve("hudi_data")));
+                queryRunner.installPlugin(new MemoryBlobCachePlugin());
+                queryRunner.loadBlobCacheManager("memory", 
Map.of("fs.memory-cache.max-size", "128MB"));
                 queryRunner.createCatalog("hudi", "hudi", connectorProperties);
 
                 // Hudi connector does not support creating schema or any 
other write operations
@@ -153,19 +156,19 @@ public final class HudiQueryRunner
         }
     }
 
-    public static final class HudiMinioQueryRunnerMain
+    public static final class HudiFlociQueryRunnerMain
     {
-        private HudiMinioQueryRunnerMain() {}
+        private HudiFlociQueryRunnerMain() {}
 
         public static void main(String[] args)
                 throws Exception
         {
             Logging.initialize();
-            Logger log = Logger.get(HudiMinioQueryRunnerMain.class);
+            Logger log = Logger.get(HudiFlociQueryRunnerMain.class);
 
-            Hive3MinioDataLake hiveMinioDataLake = new 
Hive3MinioDataLake("test-bucket");
-            hiveMinioDataLake.start();
-            QueryRunner queryRunner = builder(hiveMinioDataLake)
+            Hive3FlociDataLake hiveFlociDataLake = new 
Hive3FlociDataLake("test-bucket");
+            hiveFlociDataLake.start();
+            QueryRunner queryRunner = builder(hiveFlociDataLake)
                     .addCoordinatorProperty("http-server.http.port", "8080")
                     .setDataLoader(new 
TpchHudiTablesInitializer(TpchTable.getTables()))
                     .build();
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCacheFileOperations.java
 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCacheFileOperations.java
index 22f569dcf50d..e245b0e61396 100644
--- 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCacheFileOperations.java
+++ 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCacheFileOperations.java
@@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMultiset;
 import com.google.common.collect.Multiset;
 import io.airlift.units.Duration;
+import io.trino.blob.cache.alluxio.AlluxioBlobCachePlugin;
 import io.trino.plugin.hudi.testing.ResourceHudiTablesInitializer;
 import io.trino.plugin.hudi.util.FileOperationUtils.FileOperation;
 import io.trino.testing.AbstractTestQueryFramework;
@@ -63,8 +64,6 @@ public class TestHudiAlluxioCacheFileOperations
         Map<String, String> hudiProperties = ImmutableMap.<String, 
String>builder()
                 .put("hudi.metadata-enabled", "true")
                 .put("fs.cache.enabled", "true")
-                .put("fs.cache.directories", 
cacheDirectory.toAbsolutePath().toString())
-                .put("fs.cache.max-sizes", "100MB")
                 .put("hudi.metadata.cache.enabled", "false")
                 // Disable the async table-statistics refresh: on the first 
query it reads the index
                 // definitions and table-property files (and the metadata 
table) on a background
@@ -77,6 +76,11 @@ public class TestHudiAlluxioCacheFileOperations
         return HudiQueryRunner.builder()
                 .addConnectorProperties(hudiProperties)
                 .setDataLoader(new ResourceHudiTablesInitializer())
+                .withPlugin(new AlluxioBlobCachePlugin())
+                .withBlobCache("alluxio", ImmutableMap.<String, 
String>builder()
+                        .put("fs.cache.directories", 
cacheDirectory.toAbsolutePath().toString())
+                        .put("fs.cache.max-sizes", "100MB")
+                        .buildOrThrow())
                 .setWorkerCount(0)
                 .build();
     }
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCachingSmokeTest.java
 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCachingSmokeTest.java
index 9c191a20e34c..0e5eea5d1df9 100644
--- 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCachingSmokeTest.java
+++ 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiAlluxioCachingSmokeTest.java
@@ -21,6 +21,8 @@ import org.junit.jupiter.api.parallel.ResourceLock;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Map;
+import java.util.Optional;
 
 import static com.google.common.io.MoreFiles.deleteRecursively;
 import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE;
@@ -52,8 +54,15 @@ public class TestHudiAlluxioCachingSmokeTest
     {
         return ImmutableMap.<String, String>builder()
                 .put("fs.cache.enabled", "true")
+                .buildOrThrow();
+    }
+
+    @Override
+    protected Optional<Map<String, String>> getBlobCacheProperties()
+    {
+        return Optional.of(ImmutableMap.<String, String>builder()
                 .put("fs.cache.directories", 
cacheDirectory.toAbsolutePath().toString())
                 .put("fs.cache.max-sizes", "1GB")
-                .buildOrThrow();
+                .buildOrThrow());
     }
 }
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMinioConnectorSmokeTest.java
 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiFlociConnectorSmokeTest.java
similarity index 77%
rename from 
hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMinioConnectorSmokeTest.java
rename to 
hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiFlociConnectorSmokeTest.java
index 5fa1332073cd..b17b36001ce1 100644
--- 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMinioConnectorSmokeTest.java
+++ 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiFlociConnectorSmokeTest.java
@@ -13,7 +13,7 @@
  */
 package io.trino.plugin.hudi;
 
-import io.trino.plugin.hive.containers.Hive3MinioDataLake;
+import io.trino.plugin.hive.containers.Hive3FlociDataLake;
 import io.trino.plugin.hudi.testing.TpchHudiTablesInitializer;
 import io.trino.testing.QueryRunner;
 
@@ -21,7 +21,7 @@ import static 
io.trino.plugin.hive.containers.HiveHadoop.HIVE3_IMAGE;
 import static io.trino.plugin.hudi.testing.HudiTestUtils.COLUMNS_TO_HIDE;
 import static io.trino.testing.TestingNames.randomNameSuffix;
 
-public class TestHudiMinioConnectorSmokeTest
+public class TestHudiFlociConnectorSmokeTest
         extends BaseHudiConnectorSmokeTest
 {
     @Override
@@ -29,11 +29,10 @@ public class TestHudiMinioConnectorSmokeTest
             throws Exception
     {
         String bucketName = "test-hudi-connector-" + randomNameSuffix();
-        Hive3MinioDataLake hiveMinioDataLake = closeAfterClass(new 
Hive3MinioDataLake(bucketName, HIVE3_IMAGE));
-        hiveMinioDataLake.start();
-        hiveMinioDataLake.getMinioClient().ensureBucketExists(bucketName);
+        Hive3FlociDataLake hiveFlociDataLake = closeAfterClass(new 
Hive3FlociDataLake(bucketName, HIVE3_IMAGE));
+        hiveFlociDataLake.start();
 
-        return HudiQueryRunner.builder(hiveMinioDataLake)
+        return HudiQueryRunner.builder(hiveFlociDataLake)
                 .addConnectorProperty("hudi.columns-to-hide", COLUMNS_TO_HIDE)
                 .setDataLoader(new 
TpchHudiTablesInitializer(REQUIRED_TPCH_TABLES))
                 .build();
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMemoryCacheFileOperations.java
 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMemoryCacheFileOperations.java
index b5ada5741411..4ff361b8e6c1 100644
--- 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMemoryCacheFileOperations.java
+++ 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiMemoryCacheFileOperations.java
@@ -76,7 +76,7 @@ public class TestHudiMemoryCacheFileOperations
         assertFileSystemAccesses(
                 query,
                 ImmutableMultiset.<FileOperation>builder()
-                        .addCopies(new 
FileOperation("FileSystemCache.cacheInput", DATA), 2)
+                        .addCopies(new FileOperation("BlobCache.get", DATA), 2)
                         .addCopies(new FileOperation("InputFile.newStream", 
INDEX_DEFINITION), 2)
                         .add(new FileOperation("InputFile.newStream", 
METADATA_TABLE_PROPERTIES))
                         .addCopies(new FileOperation("InputFile.newStream", 
TABLE_PROPERTIES), 2)
@@ -85,7 +85,7 @@ public class TestHudiMemoryCacheFileOperations
         assertFileSystemAccesses(
                 query,
                 ImmutableMultiset.<FileOperation>builder()
-                        .addCopies(new 
FileOperation("FileSystemCache.cacheInput", DATA), 2)
+                        .addCopies(new FileOperation("BlobCache.get", DATA), 2)
                         .addCopies(new FileOperation("InputFile.newStream", 
INDEX_DEFINITION), 2)
                         .add(new FileOperation("InputFile.newStream", 
METADATA_TABLE_PROPERTIES))
                         .addCopies(new FileOperation("InputFile.newStream", 
TABLE_PROPERTIES), 2)
@@ -102,7 +102,7 @@ public class TestHudiMemoryCacheFileOperations
 
         assertFileSystemAccesses(query,
                 ImmutableMultiset.<FileOperation>builder()
-                        .addCopies(new 
FileOperation("FileSystemCache.cacheInput", DATA), 6)
+                        .addCopies(new FileOperation("BlobCache.get", DATA), 6)
                         .addCopies(new FileOperation("InputFile.newStream", 
INDEX_DEFINITION), 4)
                         .addCopies(new FileOperation("InputFile.newStream", 
METADATA_TABLE_PROPERTIES), 2)
                         .addCopies(new FileOperation("InputFile.newStream", 
TABLE_PROPERTIES), 4)
@@ -110,7 +110,7 @@ public class TestHudiMemoryCacheFileOperations
 
         assertFileSystemAccesses(query,
                 ImmutableMultiset.<FileOperation>builder()
-                        .addCopies(new 
FileOperation("FileSystemCache.cacheInput", DATA), 6)
+                        .addCopies(new FileOperation("BlobCache.get", DATA), 6)
                         .addCopies(new FileOperation("InputFile.newStream", 
INDEX_DEFINITION), 4)
                         .addCopies(new FileOperation("InputFile.newStream", 
METADATA_TABLE_PROPERTIES), 2)
                         .addCopies(new FileOperation("InputFile.newStream", 
TABLE_PROPERTIES), 4)
@@ -127,7 +127,7 @@ public class TestHudiMemoryCacheFileOperations
     private static Multiset<FileOperation> getFileOperations(QueryRunner 
queryRunner)
     {
         return queryRunner.getSpans().stream()
-                .filter(span -> span.getName().startsWith("Input.") || 
span.getName().startsWith("InputFile.") || 
span.getName().startsWith("FileSystemCache."))
+                .filter(span -> span.getName().startsWith("Input.") || 
span.getName().startsWith("InputFile.") || 
span.getName().startsWith("FileSystemCache.") || 
span.getName().startsWith("BlobCache."))
                 .filter(span -> 
!span.getName().startsWith("InputFile.newInput"))
                 .filter(span -> !span.getName().startsWith("InputFile.exists"))
                 .filter(span -> 
!isTrinoSchemaOrPermissions(getFileLocation(span)))
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSmokeTest.java 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSmokeTest.java
index 6f8971f3bbe6..51d0ae1a375a 100644
--- a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSmokeTest.java
+++ b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSmokeTest.java
@@ -17,6 +17,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.io.Resources;
 import io.trino.Session;
+import io.trino.blob.cache.alluxio.AlluxioBlobCachePlugin;
 import io.trino.filesystem.Location;
 import io.trino.filesystem.TrinoFileSystemFactory;
 import io.trino.filesystem.TrinoInputFile;
@@ -100,10 +101,13 @@ public class TestHudiSmokeTest
     protected QueryRunner createQueryRunner()
             throws Exception
     {
-        return HudiQueryRunner.builder()
+        HudiQueryRunner.Builder builder = HudiQueryRunner.builder()
                 .setDataLoader(new ResourceHudiTablesInitializer())
-                .addConnectorProperties(getAdditionalHudiProperties())
-                .build();
+                .addConnectorProperties(getAdditionalHudiProperties());
+        getBlobCacheProperties().ifPresent(cacheProperties -> builder
+                .withPlugin(new AlluxioBlobCachePlugin())
+                .withBlobCache("alluxio", cacheProperties));
+        return builder.build();
     }
 
     protected ImmutableMap<String, String> getAdditionalHudiProperties()
@@ -111,6 +115,11 @@ public class TestHudiSmokeTest
         return ImmutableMap.of();
     }
 
+    protected Optional<Map<String, String>> getBlobCacheProperties()
+    {
+        return Optional.empty();
+    }
+
     @Test
     public void testReadNonPartitionedTable()
     {
@@ -928,6 +937,42 @@ public class TestHudiSmokeTest
         assertQuery(query, "VALUES (1, 'a1', 100.0, 1000), (3, 'a3', 101.0, 
1001)");
     }
 
+    @ParameterizedTest
+    @EnumSource(
+            value = ResourceHudiTablesInitializer.TestingTable.class,
+            names = {"HUDI_MULTI_FG_PT_V6_MOR", "HUDI_MULTI_FG_PT_V8_MOR"})
+    public void 
testDynamicFilterEliminatesAllSplits(ResourceHudiTablesInitializer.TestingTable 
table)
+    {
+        Session session = SessionBuilder
+                .from(getSession())
+                .withDynamicFilterTimeout("10s")
+                .build();
+        final String tableIdentifier = "hudi:tests." + table.getRoTableName();
+
+        // The build side matches no rows, so the completed dynamic filter is 
NONE and the
+        // probe-side split source must report itself finished instead of 
draining the queue
+        @Language("SQL") String query = "SELECT t1.id FROM " +
+                table + " t1 " +
+                "INNER JOIN " + table + " t2 ON t1.id = t2.id " +
+                "WHERE t2.price < 0";
+        MaterializedResult explainRes = getQueryRunner().execute(session, 
"EXPLAIN ANALYZE " + query);
+        Pattern scanFilterInputRowsPattern = 
getScanFilterInputRowsPattern(tableIdentifier);
+        Matcher matcher = 
scanFilterInputRowsPattern.matcher(explainRes.toString());
+        assertThat(matcher.find())
+                .withFailMessage("Could not find 'ScanFilter' for table '%s' 
with 'dynamicFilters' and 'Input: X rows' stats in EXPLAIN output.\nOutput 
was:\n%s",
+                        tableIdentifier, explainRes.toString())
+                .isTrue();
+
+        // Zero probe-side input rows pins split elimination at the source: 
without the NONE
+        // short-circuit the probe would scan all rows and the join would 
discard them, which
+        // returns the same empty result but reads Input: 4 rows here
+        assertThat(Long.parseLong(matcher.group(1)))
+                .describedAs("Probe side (%s) should read no rows when the 
dynamic filter is NONE", tableIdentifier)
+                .isEqualTo(0);
+
+        assertThat(getQueryRunner().execute(session, 
query).getRowCount()).isEqualTo(0);
+    }
+
     @ParameterizedTest
     @EnumSource(
             value = ResourceHudiTablesInitializer.TestingTable.class,
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSplitSource.java 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSplitSource.java
new file mode 100644
index 000000000000..567d4b776459
--- /dev/null
+++ b/hudi-trino/src/test/java/io/trino/plugin/hudi/TestHudiSplitSource.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed 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 io.trino.plugin.hudi;
+
+import io.airlift.units.Duration;
+import io.trino.plugin.hive.util.AsyncQueue;
+import io.trino.plugin.hive.util.ThrottledAsyncQueue;
+import io.trino.spi.TrinoException;
+import io.trino.spi.connector.ConnectorSplit;
+import io.trino.spi.connector.DynamicFilterSnapshot;
+import io.trino.spi.connector.SchemaTableName;
+import io.trino.spi.predicate.TupleDomain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class TestHudiSplitSource
+{
+    private static final SchemaTableName TABLE = new SchemaTableName("tests", 
"split_source_test");
+    private static final Duration TIMEOUT = new Duration(10, SECONDS);
+    private static final ConnectorSplit DUMMY_SPLIT = new ConnectorSplit() {};
+
+    private final ExecutorService executor = Executors.newCachedThreadPool();
+    private final ScheduledExecutorService scheduler = 
Executors.newSingleThreadScheduledExecutor();
+
+    @AfterAll
+    public void tearDown()
+    {
+        executor.shutdownNow();
+        scheduler.shutdownNow();
+    }
+
+    @Test
+    public void testNoneDynamicFilterTerminatesSource()
+            throws Exception
+    {
+        AsyncQueue<ConnectorSplit> queue = new ThrottledAsyncQueue<>(100, 100, 
executor);
+        // Loader that stays "in flight": splits are queued but the queue is 
never finished,
+        // so only the early-termination path can make the source report 
finished
+        HudiSplitSource splitSource = new HudiSplitSource(queue, scheduler, 
(q, errorListener) -> () -> q.offer(DUMMY_SPLIT), TABLE, TIMEOUT);
+
+        CompletableFuture<List<ConnectorSplit>> batch =
+                splitSource.getNextBatch(10, new 
DynamicFilterSnapshot(TupleDomain.none(), true));
+
+        assertThat(batch).isCompletedWithValueMatching(List::isEmpty);
+        assertThat(splitSource.isFinished()).isTrue();
+    }
+
+    @Test
+    public void testLoaderFailureBlocksFinishedAndSurfaces()
+            throws Exception
+    {
+        AsyncQueue<ConnectorSplit> queue = new ThrottledAsyncQueue<>(100, 100, 
executor);
+        HudiSplitSource splitSource = new HudiSplitSource(
+                queue,
+                scheduler,
+                (q, errorListener) -> () -> errorListener.accept(new 
RuntimeException("boom")),
+                TABLE,
+                TIMEOUT);
+        awaitQueueFinished(queue);
+
+        // The failed load finished the queue, but the source must not claim 
finished while the
+        // failure is undelivered; the next batch is what surfaces it
+        assertThat(splitSource.isFinished()).isFalse();
+        CompletableFuture<List<ConnectorSplit>> batch =
+                splitSource.getNextBatch(10, new 
DynamicFilterSnapshot(TupleDomain.all(), false));
+        assertThatThrownBy(batch::join)
+                .hasCauseInstanceOf(TrinoException.class)
+                .hasMessageContaining("Failed to generate splits");
+    }
+
+    @Test
+    public void testCompletedLoaderFinishesNormally()
+            throws Exception
+    {
+        AsyncQueue<ConnectorSplit> queue = new ThrottledAsyncQueue<>(100, 100, 
executor);
+        HudiSplitSource splitSource = new HudiSplitSource(
+                queue,
+                scheduler,
+                (q, errorListener) -> (Runnable) q::finish,
+                TABLE,
+                TIMEOUT);
+        awaitQueueFinished(queue);
+
+        CompletableFuture<List<ConnectorSplit>> batch =
+                splitSource.getNextBatch(10, new 
DynamicFilterSnapshot(TupleDomain.all(), false));
+        assertThat(batch.join()).isEmpty();
+        assertThat(splitSource.isFinished()).isTrue();
+    }
+
+    private static void awaitQueueFinished(AsyncQueue<ConnectorSplit> queue)
+            throws InterruptedException
+    {
+        for (int i = 0; i < 500 && !queue.isFinished(); i++) {
+            Thread.sleep(10);
+        }
+        assertThat(queue.isFinished()).isTrue();
+    }
+}
diff --git 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/util/TestTupleDomainUtilsTest.java
 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/util/TestTupleDomainUtilsTest.java
index 64becba2ce60..e6e4557580ca 100644
--- 
a/hudi-trino/src/test/java/io/trino/plugin/hudi/util/TestTupleDomainUtilsTest.java
+++ 
b/hudi-trino/src/test/java/io/trino/plugin/hudi/util/TestTupleDomainUtilsTest.java
@@ -176,7 +176,7 @@ class TestTupleDomainUtilsTest
         // "other_col" is an irrelevant column
         TupleDomain<String> tupleDomain = TupleDomain.withColumnDomains(Map.of(
                 "key1", Domain.singleValue(BIGINT, 1L), // EQUALS
-                "key2", Domain.multipleValues(VARCHAR, List.of("a", "b")), // 
IN
+                "key2", Domain.multipleValues(VARCHAR, 
List.of(Slices.utf8Slice("a"), Slices.utf8Slice("b"))), // IN
                 "other_col", 
Domain.create(ValueSet.ofRanges(Range.greaterThan(BIGINT, 10L)), false)));
         List<String> sourceFields = List.of("key1", "key2");
         assertThat(TupleDomainUtils.areDomainsInOrEqualOnly(tupleDomain, 
sourceFields)).isTrue();
diff --git a/pom.xml b/pom.xml
index f64fde294508..ec7c9c7cafe9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -131,7 +131,14 @@
     <hive.parquet.version>1.10.1</hive.parquet.version>
     <hive.avro.version>1.11.4</hive.avro.version>
     <presto.version>0.273</presto.version>
-    <trino.version>481</trino.version>
+    <!-- trino.sha is the exact trinodb/trino commit hudi-trino builds 
against; its project
+         version must equal trino.version and the two advance only together. 
trino.e2e.version is
+         the latest released Trino (e2e server image, trino-jdbc for the integ 
tests); the nightly
+         pin-advance job refreshes all three, humans merge its bot/trino-pin 
branch. Keep each
+         property on one line: the workflows and 
scripts/trino/bootstrap_trino.sh read them with sed. -->
+    <trino.version>484-SNAPSHOT</trino.version>
+    <trino.sha>5b82ec9e7116ec1ed3a83f4cc2f8cf9aaa87b12f</trino.sha>
+    <trino.e2e.version>483</trino.e2e.version>
     <hive.exec.classifier>core</hive.exec.classifier>
     <metrics.version>4.1.1</metrics.version>
     <orc.spark.version>1.6.0</orc.spark.version>
@@ -1758,7 +1765,7 @@
       <dependency>
         <groupId>io.trino</groupId>
         <artifactId>trino-jdbc</artifactId>
-        <version>${trino.version}</version>
+        <version>${trino.e2e.version}</version>
       </dependency>
 
       <!-- Zookeeper -->
diff --git a/release/release_guide.md b/release/release_guide.md
index ed78098f66c1..3175b63b96c6 100644
--- a/release/release_guide.md
+++ b/release/release_guide.md
@@ -290,6 +290,31 @@ Here is how to go about a bug fix release.
 - Go to apache/hudi repo locally and pull this branch. Here after you can work 
on this branch and push to origin when need be.
 - Do not forget to set the env variables from above section.
 
+## hudi-trino Trino pin-back
+
+On master hudi-trino tracks `trinodb/trino` master at the commit in 
`trino.sha`, whose `trino.version` is a
+`-SNAPSHOT` that resolves from nowhere but a local build. A release must 
depend on a released Trino, and the pin-back
+must land on the release branch before the source release is generated (see 
"Build a release candidate", the Generate
+Source Release step) -- otherwise the voted tarball ships a `-SNAPSHOT` Trino 
pin that cannot be built from Central.
+
+1. Wait for the latest released Trino `NNN` to be available on Maven Central.
+2. In a `trinodb/trino` checkout, find the tagged commit: `TAG_SHA=$(git 
rev-list -n1 NNN)`.
+3. If the pin is behind the tag, advance master's pin to `TAG_SHA` first by 
dispatching the
+   `Hudi Trino SPI Compatibility` workflow with `trino_ref=NNN` (it then 
verifies and pins exactly that tag rather
+   than master HEAD) and merging the pin PR a committer opens from the pushed 
`bot/trino-pin` branch. If the pin is ahead of the tag, enumerate the 
adaptations that would be lost with
+   `git log NNN..<pin> -- core/trino-spi lib/trino-filesystem 
lib/trino-filesystem-manager lib/trino-hdfs lib/trino-memory-context`
+   and revert them forward on the release branch only, never on master.
+4. On the release branch set `trino.version=NNN`, `trino.sha=TAG_SHA` and 
`trino.e2e.version=NNN` in the root
+   pom, the `<parent>` version in `docker/trino/shim/pom.xml`, and the `ARG 
TRINO_VERSION` default in
+   `docker/trino/Dockerfile` (`build_image.sh` reads `trino.e2e.version` from 
the root pom). Re-check SPI-surface-coupled
+   dependency scopes against `NNN` (e.g. `jts-core` is `provided` because it 
joined the Trino SPI surface in 482;
+   the shim's SpiDependencyChecker fails the build loudly if a scope no longer 
matches the target release).
+5. Verify the released Trino resolves from Central against an empty local 
repository
+   (scope the check to io.trino: the module's hudi siblings are not on Central 
until this release completes):
+   `mvn dependency:get -Dartifact=io.trino:trino-hive:NNN 
-Dmaven.repo.local=$(mktemp -d)`
+6. CI and the E2E workflow then run with zero SPI drift; the staging deploy 
flow in "Build a release candidate"
+   is unchanged.
+
 ## Verify that a Release Build Works
 
 Run "mvn -Prelease clean install" to ensure that the build processes are in 
good shape. // You need to execute this command once you have the release 
branch in apache/hudi
@@ -429,6 +454,8 @@ Set up a few environment variables to simplify Maven 
commands that follow. This
           and `./scripts/release/deploy_staging_jars_java25.sh 2>&1 | tee -a 
"/tmp/${RELEASE_VERSION}-${RC_NUM}.deploy3.log"`.
           This step must run after the Java 11 step in 9.4.1, which installs 
the upstream Hudi modules that hudi-trino
           resolves from the local m2 (the script does not pass `-am` because 
Lombok cannot run on JDK 25).
+       4. The hudi-trino Trino pin-back already happened when the release 
branch was cut (see the
+          "hudi-trino Trino pin-back" section under "Cut a release branch"); 
the Java 25 deploy needs no extra steps.
    5. Note that each of the Java 17 and Java 25 builds uploads its artifacts 
to its own separate staging repo. Use the
       `copy_staging_repo.sh` script once per extra staging repo to copy all 
artifacts into the Java 11 staging repo
       so that all artifacts stay in the same repo.
diff --git a/rfc/rfc-105/rfc-105.md b/rfc/rfc-105/rfc-105.md
index 51c7aef2fb90..dce625a08cb3 100644
--- a/rfc/rfc-105/rfc-105.md
+++ b/rfc/rfc-105/rfc-105.md
@@ -125,7 +125,7 @@ apache/hudi : hudi-trino-plugin/    (Maven profile 
-Phudi-trino,
 | `src/main/java/io/trino/plugin/hudi/HudiPlugin.java` | Implements 
`io.trino.spi.Plugin`. Single method returning `new HudiConnectorFactory()` 
(from the `hudi-trino` artifact). ~10 lines. |
 | `src/main/resources/META-INF/services/io.trino.spi.Plugin` | Service-loader 
pointer to `io.trino.plugin.hudi.HudiPlugin`. |
 | `pom.xml` | `<packaging>trino-plugin</packaging>`; pins 
`org.apache.hudi:hudi-trino:<version>`; SPI deps as `provided`. |
-| `src/test/java/...` | All current Trino-side tests stay: `HudiQueryRunner`, 
`TestHudiSmokeTest`, `TestHudiMinioConnectorSmokeTest`, 
`TestHudiConnectorTest`, `TestHudiSharedMetastore`, `TestHudiSystemTables`, 
`TestHudiPlugin`, `TestHudiConfig`, plus data initializers. Required by the 
Trino-side test-coverage commitment. |
+| `src/test/java/...` | All current Trino-side tests stay: `HudiQueryRunner`, 
`TestHudiSmokeTest`, `TestHudiFlociConnectorSmokeTest`, 
`TestHudiConnectorTest`, `TestHudiSharedMetastore`, `TestHudiSystemTables`, 
`TestHudiPlugin`, `TestHudiConfig`, plus data initializers. Required by the 
Trino-side test-coverage commitment. |
 
 #### Hudi-side `hudi-trino-plugin/` (the engine)
 
@@ -187,7 +187,7 @@ On the Trino side, existing CI continues to build and test 
`plugin/trino-hudi`,
 
 ### Test strategy
 
-**Full test duplication.** The Trino-side smoke tests (`TestHudiSmokeTest`, 
`TestHudiMinioConnectorSmokeTest`, `TestHudiConnectorTest`, etc.) are mirrored 
on the Hudi side and additionally extended.
+**Full test duplication.** The Trino-side smoke tests (`TestHudiSmokeTest`, 
`TestHudiFlociConnectorSmokeTest`, `TestHudiConnectorTest`, etc.) are mirrored 
on the Hudi side and additionally extended.
 
 - **Trino side runs them** on every Trino PR — fulfilling the Trino-side 
test-coverage commitment.
 - **Hudi side runs them** on every Hudi PR touching `hudi-trino-plugin` — so 
Hudi contributors catch regressions before they ship in a Hudi release. The 
Hudi-side suite is also **expanded** with more granular unit tests covering 
split generation edge cases, all eight index-support strategies, the MOR 
record-merging path, lazy-commit-time snapshot isolation, and the cache-key 
provider.
diff --git a/scripts/trino/bootstrap_trino.sh b/scripts/trino/bootstrap_trino.sh
new file mode 100755
index 000000000000..835c6389145d
--- /dev/null
+++ b/scripts/trino/bootstrap_trino.sh
@@ -0,0 +1,170 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+##
+## Builds the trinodb/trino modules that hudi-trino compiles and tests against
+## and installs them into the local Maven repository.
+##
+## On master, hudi-trino tracks trinodb/trino master at the commit pinned by 
the
+## <trino.sha> property in the root pom (whose project version is 
<trino.version>,
+## e.g. 484-SNAPSHOT). Trino publishes no SNAPSHOT artifacts, so every io.trino
+## dependency must be installed from source by this script before hudi-trino 
can
+## build. On release branches <trino.version> is a released number and only the
+## test-jars (never published by Trino) need this script.
+##
+## Usage: bootstrap_trino.sh <path-to-trino-checkout> [--ref <sha>] 
[--skip-checkout] [--keep-m2]
+##
+##   <path-to-trino-checkout>  a trinodb/trino git checkout (clean worktree)
+##   --ref <sha>               build at this commit instead of the pinned 
<trino.sha>
+##                             (used by the nightly pin-advance workflow at 
trino HEAD;
+##                             relaxes the version cross-check to a warning)
+##   --skip-checkout           assume the worktree is already at the right 
commit
+##                             (CI checks out the SHA itself via 
actions/checkout)
+##   --keep-m2                 do not purge ~/.m2/repository/io/trino first
+##                             (the purge guards against stale artifacts under 
the
+##                             same SNAPSHOT coordinates from an older pin)
+##
+
+set -euo pipefail
+
+HUDI_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
+
+TRINO_REPO=""
+REF=""
+SKIP_CHECKOUT="false"
+KEEP_M2="false"
+
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+    --ref)
+      REF="$2"
+      shift 2
+      ;;
+    --skip-checkout)
+      SKIP_CHECKOUT="true"
+      shift
+      ;;
+    --keep-m2)
+      KEEP_M2="true"
+      shift
+      ;;
+    -h|--help)
+      grep '^##' "$0" | sed 's/^## \{0,1\}//'
+      exit 0
+      ;;
+    *)
+      if [[ -z "$TRINO_REPO" ]]; then
+        TRINO_REPO="$1"
+        shift
+      else
+        echo "ERROR: unexpected argument: $1" >&2
+        exit 1
+      fi
+      ;;
+  esac
+done
+
+if [[ -z "$TRINO_REPO" || ! -d "$TRINO_REPO/.git" && ! -f "$TRINO_REPO/.git" 
]]; then
+  echo "ERROR: first argument must be a trinodb/trino git checkout" >&2
+  echo "Usage: $0 <path-to-trino-checkout> [--ref <sha>] [--skip-checkout] 
[--keep-m2]" >&2
+  exit 1
+fi
+
+# The pin lives in the root pom; keep each property on one line (this sed and 
the
+# CI workflows depend on it).
+PINNED_SHA=$(sed -n 's|.*<trino.sha>\(.*\)</trino.sha>.*|\1|p' 
"$HUDI_ROOT/pom.xml")
+PINNED_VERSION=$(sed -n 's|.*<trino.version>\(.*\)</trino.version>.*|\1|p' 
"$HUDI_ROOT/pom.xml")
+
+if [[ -z "$PINNED_VERSION" ]]; then
+  echo "ERROR: could not read <trino.version> from $HUDI_ROOT/pom.xml" >&2
+  exit 1
+fi
+
+RELAXED_VERSION_CHECK="false"
+if [[ -n "$REF" ]]; then
+  RELAXED_VERSION_CHECK="true"
+else
+  REF="$PINNED_SHA"
+  if [[ -z "$REF" ]]; then
+    echo "ERROR: could not read <trino.sha> from $HUDI_ROOT/pom.xml and no 
--ref given" >&2
+    exit 1
+  fi
+fi
+
+# JDK gate: trino at head enforces JDK 25.
+JAVA_MAJOR=$(java -version 2>&1 | awk -F[\".] '/version/ {print $2}')
+if [[ "$JAVA_MAJOR" != "25" ]]; then
+  echo "ERROR: JDK 25 required to build trino (found major version: 
${JAVA_MAJOR:-unknown})." >&2
+  echo "Hint: export JAVA_HOME=\$(/usr/libexec/java_home -v 25)" >&2
+  exit 1
+fi
+
+if ! git -C "$TRINO_REPO" rev-parse --verify --quiet "${REF}^{commit}" > 
/dev/null; then
+  echo "ERROR: commit $REF not present in $TRINO_REPO" >&2
+  echo "Hint: git -C $TRINO_REPO fetch https://github.com/trinodb/trino.git 
master --tags" >&2
+  exit 1
+fi
+
+if [[ "$SKIP_CHECKOUT" == "false" ]]; then
+  # Refuse tracked modifications; untracked files are harmless for a checkout.
+  if [[ -n "$(git -C "$TRINO_REPO" status --porcelain -uno)" ]]; then
+    echo "ERROR: $TRINO_REPO has uncommitted tracked changes; commit or stash 
them first" >&2
+    exit 1
+  fi
+  git -C "$TRINO_REPO" -c advice.detachedHead=false checkout --detach "$REF"
+fi
+
+ACTUAL_VERSION=$("$TRINO_REPO/mvnw" -q -N -f "$TRINO_REPO/pom.xml" 
help:evaluate -Dexpression=project.version -DforceStdout)
+if [[ "$ACTUAL_VERSION" != "$PINNED_VERSION" ]]; then
+  if [[ "$RELAXED_VERSION_CHECK" == "true" ]]; then
+    echo "WARNING: trino at $REF has version $ACTUAL_VERSION but the pom pins 
<trino.version>$PINNED_VERSION</trino.version> (version rollover?)"
+  else
+    echo "ERROR: trino at pinned sha $REF has version $ACTUAL_VERSION, but the 
root pom says <trino.version>$PINNED_VERSION</trino.version>." >&2
+    echo "The pin properties must advance together; fix the pom or your 
checkout." >&2
+    exit 1
+  fi
+fi
+
+if [[ "$KEEP_M2" == "false" ]]; then
+  # SNAPSHOT coordinates do not change when the pin does, so artifacts from an
+  # older pin are indistinguishable from current ones. Purge to be safe.
+  echo "Purging ~/.m2/repository/io/trino (use --keep-m2 to skip)"
+  rm -rf "$HOME/.m2/repository/io/trino"
+fi
+
+export MAVEN_OPTS="${MAVEN_OPTS:--Xmx4g}"
+
+# Module list rationale:
+# - trino-hive, trino-filesystem-manager, trino-parquet, trino-plugin-toolkit 
and
+#   their -am closure cover every compile-scope io.trino dependency of 
hudi-trino
+#   (trino-spi, trino-cache, trino-filesystem, trino-hive-formats,
+#   trino-memory-context, trino-metastore come in transitively).
+# - The remaining modules are hudi-trino's test-scope dependencies.
+# - trino-spi, trino-filesystem, trino-hive, trino-main are the four test-jar
+#   producers needed by the hudi-trino-tests profile; -DskipTests (NOT
+#   -Dmaven.test.skip) is load-bearing: test-jars need compiled test classes.
+# - The -am closure also installs the trino-root pom, which the hudi-trino BOM
+#   import and the docker/trino/shim parent resolve.
+# - The blob-cache plugins back the cache managers the hudi-trino tests load
+#   (memory unconditionally via HudiQueryRunner, alluxio in the caching tests).
+echo "Building trino modules at $REF (version $ACTUAL_VERSION); this takes 
roughly 10-30 minutes"
+(cd "$TRINO_REPO" && ./mvnw install -am -DskipTests -Dair.check.skip-all=true 
-T1C \
+  -pl 
:trino-hive,:trino-filesystem-manager,:trino-parquet,:trino-plugin-toolkit,:trino-main,:trino-testing,:trino-testing-containers,:trino-testing-services,:trino-client,:trino-parser,:trino-hdfs,:trino-tpch,:trino-spi,:trino-filesystem,:trino-blob-cache-memory,:trino-blob-cache-alluxio)
+
+echo "Done. io.trino artifacts for $ACTUAL_VERSION are installed in ~/.m2."

Reply via email to