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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0afddbd37d [core] Use Locale.ROOT for every case conversion in main 
sources (#9771)
0afddbd37d is described below

commit 0afddbd37dbc05e10ac2670b9bbd959dc2344580
Author: YangJie <[email protected]>
AuthorDate: Mon Sep 21 23:40:58 2026 -0400

    [core] Use Locale.ROOT for every case conversion in main sources (#9771)
---
 .../main/java/org/apache/paimon/CoreOptions.java   |   7 +-
 .../org/apache/paimon/options/OptionsUtils.java    |   2 +-
 .../java/org/apache/paimon/rest/HttpClient.java    |   5 +-
 .../paimon/rest/auth/DLFAuthProviderFactory.java   |   3 +-
 .../apache/paimon/rest/auth/DLFDefaultSigner.java  |  15 ++-
 .../apache/paimon/rest/auth/DLFOpenApiSigner.java  |   2 +-
 .../apache/paimon/types/DataTypeJsonParser.java    |   5 +-
 .../main/java/org/apache/paimon/types/RowKind.java |   4 +-
 .../java/org/apache/paimon/utils/StringUtils.java  |   9 +-
 .../apache/paimon/TurkishLocaleParsingTest.java    |  73 +++++++++++
 .../benchmark/metric/cpu/OperatingSystem.java      |   4 +-
 .../compression/BlockCompressionFactory.java       |   4 +-
 .../java/org/apache/paimon/format/FileFormat.java  |  12 +-
 .../src/main/java/org/apache/paimon/fs/FileIO.java |   5 +-
 .../paimon/globalindex/HybridSearchRanker.java     |   3 +-
 .../apache/paimon/lookup/sort/db/LocalKvDb.java    |   4 +-
 .../paimon/statistics/SimpleColStatsCollector.java |   3 +-
 .../apache/paimon/utils/BlobDescriptorUtils.java   |   3 +-
 .../java/org/apache/paimon/utils/JNIUtils.java     |   3 +-
 .../org/apache/paimon/utils/OperatingSystem.java   |   4 +-
 .../paimon/format/FileFormatPrefixOptionsTest.java | 101 +++++++++++++++
 .../org/apache/paimon/utils/StringUtilsTest.java   |  16 +++
 .../org/apache/paimon/catalog/CatalogUtils.java    |   3 +-
 .../java/org/apache/paimon/disk/FileIOChannel.java |   4 +-
 .../apache/paimon/iceberg/IcebergPathFactory.java  |   4 +-
 .../paimon/jdbc/DistributedLockDialectFactory.java |   4 +-
 .../paimon/lookup/local/LocalKvStateFactory.java   |   3 +-
 .../paimon/table/ChainTableFileStoreTable.java     |   3 +-
 .../java/org/apache/paimon/table/FormatTable.java  |   3 +-
 .../table/source/DataEvolutionVectorScan.java      |   3 +-
 .../paimon/table/system/SystemTableLoader.java     |   3 +-
 .../apache/paimon/utils/PartitionPathUtils.java    |   3 +-
 .../configuration/ConfigOptionsDocGenerator.java   |   3 +-
 .../java/org/apache/paimon/cosn/COSNFileIO.java    |  11 +-
 .../java/org/apache/paimon/jindo/JindoFileIO.java  |  11 +-
 .../main/java/org/apache/paimon/obs/OBSFileIO.java |  11 +-
 .../main/java/org/apache/paimon/oss/OSSFileIO.java |  11 +-
 .../flink/action/cdc/CdcActionCommonUtils.java     |   3 +-
 .../apache/paimon/flink/action/cdc/Expression.java |   7 +-
 .../flink/action/cdc/SyncDatabaseActionBase.java   |  11 +-
 .../flink/action/cdc/TableNameConverter.java       |  15 ++-
 .../paimon/flink/action/cdc/TypeMapping.java       |   5 +-
 .../flink/action/cdc/format/DataFormatFactory.java |   4 +-
 .../flink/action/cdc/kafka/KafkaActionUtils.java   |   2 +-
 .../action/cdc/mongodb/MongoDBActionUtils.java     |   3 +-
 .../action/cdc/mongodb/MongoDBSchemaUtils.java     |   4 +-
 .../cdc/mongodb/strategy/MongoVersionStrategy.java |   4 +-
 .../flink/action/cdc/mysql/MySqlTypeUtils.java     |  11 +-
 .../action/cdc/postgres/PostgresTypeUtils.java     |   4 +-
 .../apache/paimon/flink/sink/cdc/CdcRecord.java    |   6 +-
 .../action/cdc/TurkishLocaleCaseFoldingTest.java   | 142 +++++++++++++++++++++
 .../cdc/mysql/TurkishLocaleTypeNameTest.java       |  60 +++++++++
 .../paimon/flink/sink/cdc/CdcRecordTest.java       |  53 ++++++++
 .../apache/paimon/flink/FormatCatalogTable.java    |   3 +-
 .../apache/paimon/flink/action/ActionFactory.java  |   3 +-
 .../apache/paimon/flink/action/CloneAction.java    |   3 +-
 .../paimon/flink/action/MultiTablesSinkMode.java   |   5 +-
 .../paimon/flink/clone/CloneFileFormatUtils.java   |   4 +-
 .../paimon/flink/lookup/PartitionLoader.java       |   3 +-
 .../procedure/CreateGlobalIndexProcedure.java      |   3 +-
 .../flink/procedure/DropGlobalIndexProcedure.java  |   3 +-
 .../flink/source/aggregate/LocalAggregator.java    |   3 +-
 .../flink/action/MultiTablesSinkModeTest.java      |  63 +++++++++
 .../src/main/java/org/apache/orc/OrcFile.java      |   5 +-
 .../java/org/apache/paimon/hive/HiveCatalog.java   |   7 +-
 .../org/apache/paimon/hive/HiveTableUtils.java     |   5 +-
 .../apache/paimon/hive/clone/HiveCloneUtils.java   |   3 +-
 .../paimon/hive/clone/HiveTableCloneExtractor.java |  16 ++-
 .../apache/paimon/hive/pool/CachedClientPool.java  |   2 +-
 .../hive/clone/HiveTableCloneExtractorTest.java    |  69 ++++++++++
 .../paimon/hive/pool/TestCachedClientPool.java     |  18 +++
 .../java/org/apache/paimon/hive/HiveSchema.java    |   5 +-
 .../org/apache/paimon/hive/PaimonMetaHook.java     |  11 +-
 .../hive/SearchArgumentToPredicateConverter.java   |   9 +-
 .../paimon/hive/mapred/PaimonRecordReader.java     |   3 +-
 .../paimon/lumina/index/LuminaVectorMetric.java    |   4 +-
 .../lumina/index/LuminaVectorMetricTest.java       |  56 ++++++++
 .../java/org/apache/paimon/spark/SparkCatalog.java |   2 +-
 .../paimon/spark/catalog/FormatTableCatalog.java   |  13 +-
 .../org/apache/paimon/spark/SparkSource.scala      |   3 +-
 .../catalyst/analysis/PaimonFunctionResolver.scala |   4 +-
 .../catalyst/analysis/ReplacePaimonFunctions.scala |   4 +-
 .../spark/catalyst/plans/logical/CopyOptions.scala |   8 +-
 .../apache/paimon/spark/write/WriteHelper.scala    |   6 +-
 .../extensions/PaimonSqlExtensionsAstBuilder.scala |   4 +-
 .../spark/catalog/FormatTableCatalogTest.java      |  69 ++++++++++
 .../tools/ci/licensecheck/JarFileChecker.java      |   2 +-
 87 files changed, 986 insertions(+), 136 deletions(-)

diff --git a/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java 
b/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
index 2ae150ac0d..e1ccb5ed2c 100644
--- a/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
+++ b/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
@@ -3330,7 +3330,7 @@ public class CoreOptions implements Serializable {
     }
 
     public static String normalizeFileFormat(String fileFormat) {
-        return StringUtils.isEmpty(fileFormat) ? fileFormat : 
fileFormat.toLowerCase();
+        return StringUtils.isEmpty(fileFormat) ? fileFormat : 
fileFormat.toLowerCase(Locale.ROOT);
     }
 
     public String dataFilePrefix() {
@@ -4309,7 +4309,10 @@ public class CoreOptions implements Serializable {
 
     public Set<PartitionMarkDoneAction> partitionMarkDoneActions() {
         return 
Arrays.stream(options.get(PARTITION_MARK_DONE_ACTION).split(","))
-                .map(x -> PartitionMarkDoneAction.valueOf(x.replace('-', 
'_').toUpperCase()))
+                .map(
+                        x ->
+                                PartitionMarkDoneAction.valueOf(
+                                        x.replace('-', 
'_').toUpperCase(Locale.ROOT)))
                 .collect(Collectors.toCollection(HashSet::new));
     }
 
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/options/OptionsUtils.java 
b/paimon-api/src/main/java/org/apache/paimon/options/OptionsUtils.java
index a625454f39..e0ca14be9b 100644
--- a/paimon-api/src/main/java/org/apache/paimon/options/OptionsUtils.java
+++ b/paimon-api/src/main/java/org/apache/paimon/options/OptionsUtils.java
@@ -199,7 +199,7 @@ public class OptionsUtils {
             return (Boolean) o;
         }
 
-        switch (o.toString().toUpperCase()) {
+        switch (o.toString().toUpperCase(Locale.ROOT)) {
             case "TRUE":
                 return true;
             case "FALSE":
diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java 
b/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java
index 8205dfe212..2bee7d2261 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java
@@ -46,6 +46,7 @@ import javax.annotation.Nullable;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.function.Function;
@@ -221,7 +222,9 @@ public class HttpClient implements RESTClient {
                 .filter(
                         h ->
                                 h.getName() != null
-                                        && 
h.getName().toLowerCase().contains("request-id"))
+                                        && h.getName()
+                                                .toLowerCase(Locale.ROOT)
+                                                .contains("request-id"))
                 .map(Header::getValue)
                 .filter(Objects::nonNull)
                 .findFirst()
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFAuthProviderFactory.java
 
b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFAuthProviderFactory.java
index 1ce7d0a79a..3dfac337dc 100644
--- 
a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFAuthProviderFactory.java
+++ 
b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFAuthProviderFactory.java
@@ -22,6 +22,7 @@ import org.apache.paimon.options.Options;
 import org.apache.paimon.rest.RESTCatalogOptions;
 import org.apache.paimon.utils.StringUtils;
 
+import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -96,7 +97,7 @@ public class DLFAuthProviderFactory implements 
AuthProviderFactory {
         }
 
         // Check for aliyun openapi endpoints
-        if (uri.toLowerCase().contains("dlfnext")) {
+        if (uri.toLowerCase(Locale.ROOT).contains("dlfnext")) {
             return DLFOpenApiSigner.IDENTIFIER;
         }
 
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFDefaultSigner.java 
b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFDefaultSigner.java
index 76daf5c72f..d572afa88c 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFDefaultSigner.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFDefaultSigner.java
@@ -34,6 +34,7 @@ import java.util.Arrays;
 import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.TreeMap;
 
@@ -62,12 +63,12 @@ public class DLFDefaultSigner implements DLFRequestSigner {
     private static final String NEW_LINE = "\n";
     private static final List<String> SIGNED_HEADERS =
             Arrays.asList(
-                    DLF_CONTENT_MD5_HEADER_KEY.toLowerCase(),
-                    DLF_CONTENT_TYPE_KEY.toLowerCase(),
-                    DLF_CONTENT_SHA56_HEADER_KEY.toLowerCase(),
-                    DLF_DATE_HEADER_KEY.toLowerCase(),
-                    DLF_AUTH_VERSION_HEADER_KEY.toLowerCase(),
-                    DLF_SECURITY_TOKEN_HEADER_KEY.toLowerCase());
+                    DLF_CONTENT_MD5_HEADER_KEY.toLowerCase(Locale.ROOT),
+                    DLF_CONTENT_TYPE_KEY.toLowerCase(Locale.ROOT),
+                    DLF_CONTENT_SHA56_HEADER_KEY.toLowerCase(Locale.ROOT),
+                    DLF_DATE_HEADER_KEY.toLowerCase(Locale.ROOT),
+                    DLF_AUTH_VERSION_HEADER_KEY.toLowerCase(Locale.ROOT),
+                    DLF_SECURITY_TOKEN_HEADER_KEY.toLowerCase(Locale.ROOT));
 
     private final String region;
 
@@ -215,7 +216,7 @@ public class DLFDefaultSigner implements DLFRequestSigner {
         TreeMap<String, String> orderMap = new TreeMap<>();
         if (headers != null) {
             for (Map.Entry<String, String> header : headers.entrySet()) {
-                String key = header.getKey().toLowerCase();
+                String key = header.getKey().toLowerCase(Locale.ROOT);
                 if (SIGNED_HEADERS.contains(key)) {
                     orderMap.put(key, StringUtils.trim(header.getValue()));
                 }
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java 
b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java
index aaf3713828..0d4858f581 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java
@@ -184,7 +184,7 @@ public class DLFOpenApiSigner implements DLFRequestSigner {
     private static String buildCanonicalizedHeaders(Map<String, String> 
headers) {
         TreeMap<String, String> sortedHeaders = new TreeMap<>();
         for (Map.Entry<String, String> entry : headers.entrySet()) {
-            String key = entry.getKey().toLowerCase();
+            String key = entry.getKey().toLowerCase(Locale.ROOT);
             if (key.startsWith("x-acs-")) {
                 sortedHeaders.put(key, StringUtils.trim(entry.getValue()));
             }
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java 
b/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java
index 4ba89b8353..73ef59e49f 100644
--- a/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java
+++ b/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
@@ -219,7 +220,7 @@ public final class DataTypeJsonParser {
                     builder.setLength(0);
                     cursor = consumeIdentifier(builder, chars, cursor);
                     final String token = builder.toString();
-                    final String normalizedToken = token.toUpperCase();
+                    final String normalizedToken = 
token.toUpperCase(Locale.ROOT);
                     if (KEYWORDS.contains(normalizedToken)) {
                         tokens.add(new Token(TokenType.KEYWORD, cursor, 
normalizedToken));
                     } else {
@@ -350,7 +351,7 @@ public final class DataTypeJsonParser {
 
     private static final Set<String> KEYWORDS =
             Stream.of(Keyword.values())
-                    .map(k -> k.toString().toUpperCase())
+                    .map(k -> k.toString().toUpperCase(Locale.ROOT))
                     .collect(Collectors.toSet());
 
     private static class Token {
diff --git a/paimon-api/src/main/java/org/apache/paimon/types/RowKind.java 
b/paimon-api/src/main/java/org/apache/paimon/types/RowKind.java
index 17096dfbfc..f7206d2722 100644
--- a/paimon-api/src/main/java/org/apache/paimon/types/RowKind.java
+++ b/paimon-api/src/main/java/org/apache/paimon/types/RowKind.java
@@ -20,6 +20,8 @@ package org.apache.paimon.types;
 
 import org.apache.paimon.annotation.Public;
 
+import java.util.Locale;
+
 /**
  * Lists all kinds of changes that a row can describe in a changelog.
  *
@@ -135,7 +137,7 @@ public enum RowKind {
      * @see #shortString() for mapping of string and {@link RowKind}.
      */
     public static RowKind fromShortString(String value) {
-        switch (value.toUpperCase()) {
+        switch (value.toUpperCase(Locale.ROOT)) {
             case "+I":
                 return INSERT;
             case "-U":
diff --git a/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java 
b/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java
index 4a46deca4d..9e32143673 100644
--- a/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java
+++ b/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.ThreadLocalRandom;
@@ -668,7 +669,9 @@ public class StringUtils {
     }
 
     public static String toLowerCaseIfNeed(String str, boolean caseSensitive) {
-        return caseSensitive ? str : str.toLowerCase();
+        // Locale.ROOT: identifier matching must not depend on the JVM default 
locale
+        // (e.g. Turkish lowercases 'I' to a dotless glyph and breaks column 
mapping)
+        return caseSensitive ? str : str.toLowerCase(Locale.ROOT);
     }
 
     public static boolean isNumeric(final CharSequence cs) {
@@ -733,14 +736,14 @@ public class StringUtils {
         if (value == null) {
             return null;
         }
-        return value.toUpperCase();
+        return value.toUpperCase(Locale.ROOT);
     }
 
     public static String toLowerCase(String value) {
         if (value == null) {
             return null;
         }
-        return value.toLowerCase();
+        return value.toLowerCase(Locale.ROOT);
     }
 
     public static boolean isOpenBracket(char c) {
diff --git 
a/paimon-api/src/test/java/org/apache/paimon/TurkishLocaleParsingTest.java 
b/paimon-api/src/test/java/org/apache/paimon/TurkishLocaleParsingTest.java
new file mode 100644
index 0000000000..a397c25b7e
--- /dev/null
+++ b/paimon-api/src/test/java/org/apache/paimon/TurkishLocaleParsingTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon;
+
+import org.apache.paimon.options.Options;
+import org.apache.paimon.types.RowKind;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Locale;
+
+import static org.apache.paimon.CoreOptions.PARTITION_MARK_DONE_ACTION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Parsing an option value, an enum name or a protocol token uppercases or 
lowercases it first.
+ * Under a Turkish default locale 'i' maps to a dotted capital and 'I' to a 
dotless small letter, so
+ * those conversions must pin {@link Locale#ROOT} or the token no longer 
matches what it is compared
+ * against.
+ */
+class TurkishLocaleParsingTest {
+
+    private Locale original;
+
+    @BeforeEach
+    void setUp() {
+        original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+    }
+
+    @AfterEach
+    void tearDown() {
+        Locale.setDefault(original);
+    }
+
+    @Test
+    void partitionMarkDoneActionsParse() {
+        // SUCCESS_FILE and DONE_PARTITION both contain an 'i': a 
locale-sensitive uppercase
+        // turns them into names no enum constant has, and valueOf throws
+        Options options = new Options();
+        options.set(PARTITION_MARK_DONE_ACTION, "success-file,done-partition");
+
+        assertThat(new CoreOptions(options).partitionMarkDoneActions())
+                .containsExactlyInAnyOrder(
+                        CoreOptions.PartitionMarkDoneAction.SUCCESS_FILE,
+                        CoreOptions.PartitionMarkDoneAction.DONE_PARTITION);
+    }
+
+    @Test
+    void rowKindFromLowerCaseShortString() {
+        // "+i" is the only short string this can catch: Turkish differs from 
ROOT on 'i' and
+        // 'I' alone, so "-d" or "-u" would pass whichever conversion the code 
uses
+        assertThat(RowKind.fromShortString("+i")).isEqualTo(RowKind.INSERT);
+    }
+}
diff --git 
a/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/OperatingSystem.java
 
b/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/OperatingSystem.java
index 0e15ca154c..0fd6cd92a8 100644
--- 
a/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/OperatingSystem.java
+++ 
b/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/OperatingSystem.java
@@ -18,6 +18,8 @@
 
 package org.apache.paimon.benchmark.metric.cpu;
 
+import java.util.Locale;
+
 /** An enumeration indicating the operating system that the JVM runs on. */
 public enum OperatingSystem {
     LINUX,
@@ -115,7 +117,7 @@ public enum OperatingSystem {
         if (osName.startsWith(FREEBSD_OS_PREFIX)) {
             return FREE_BSD;
         }
-        String osNameLowerCase = osName.toLowerCase();
+        String osNameLowerCase = osName.toLowerCase(Locale.ROOT);
         if (osNameLowerCase.contains(SOLARIS_OS_INFIX_1)
                 || osNameLowerCase.contains(SOLARIS_OS_INFIX_2)) {
             return SOLARIS;
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/compression/BlockCompressionFactory.java
 
b/paimon-common/src/main/java/org/apache/paimon/compression/BlockCompressionFactory.java
index 60dd1657bc..563ee625bb 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/compression/BlockCompressionFactory.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/compression/BlockCompressionFactory.java
@@ -23,6 +23,8 @@ import io.airlift.compress.lzo.LzoDecompressor;
 
 import javax.annotation.Nullable;
 
+import java.util.Locale;
+
 /**
  * Each compression codec has an implementation of {@link 
BlockCompressionFactory} to create
  * compressors and decompressors.
@@ -38,7 +40,7 @@ public interface BlockCompressionFactory {
     /** Creates {@link BlockCompressionFactory} according to the 
configuration. */
     @Nullable
     static BlockCompressionFactory create(CompressOptions compression) {
-        switch (compression.compress().toUpperCase()) {
+        switch (compression.compress().toUpperCase(Locale.ROOT)) {
             case "NONE":
                 return null;
             case "ZSTD":
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/format/FileFormat.java 
b/paimon-common/src/main/java/org/apache/paimon/format/FileFormat.java
index f17c23b255..4a5f95ba04 100644
--- a/paimon-common/src/main/java/org/apache/paimon/format/FileFormat.java
+++ b/paimon-common/src/main/java/org/apache/paimon/format/FileFormat.java
@@ -30,6 +30,7 @@ import javax.annotation.Nullable;
 
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -88,16 +89,19 @@ public abstract class FileFormat {
     /** Create a {@link FileFormat} from format identifier and format options. 
*/
     public static FileFormat fromIdentifier(String identifier, FormatContext 
context) {
         return FormatFactoryUtil.discoverFactory(
-                        FileFormat.class.getClassLoader(), 
identifier.toLowerCase())
+                        FileFormat.class.getClassLoader(), 
identifier.toLowerCase(Locale.ROOT))
                 .create(context);
     }
 
     protected Options getIdentifierPrefixOptions(Options options) {
         Map<String, String> result = new HashMap<>();
-        String prefix = formatIdentifier.toLowerCase() + ".";
+        // match against the identifier as written so the suffix is sliced at 
an offset the key
+        // actually has: lower-casing can lengthen a string, and U+0130 
lower-cases to two chars
+        String prefix = formatIdentifier + ".";
+        String lowerCasePrefix = formatIdentifier.toLowerCase(Locale.ROOT) + 
".";
         for (String key : options.keySet()) {
-            if (key.toLowerCase().startsWith(prefix)) {
-                result.put(prefix + key.substring(prefix.length()), 
options.get(key));
+            if (key.regionMatches(true, 0, prefix, 0, prefix.length())) {
+                result.put(lowerCasePrefix + key.substring(prefix.length()), 
options.get(key));
             }
         }
         return new Options(result);
diff --git a/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java 
b/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java
index c6e8d02a46..16efe5f6a6 100644
--- a/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java
+++ b/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java
@@ -50,6 +50,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Queue;
@@ -584,13 +585,13 @@ public interface FileIO extends Serializable, Closeable {
         if (loader != null) {
             Set<String> options =
                     config.options().keySet().stream()
-                            .map(String::toLowerCase)
+                            .map(s -> s.toLowerCase(Locale.ROOT))
                             .collect(Collectors.toSet());
             Set<String> missOptions = new HashSet<>();
             for (String[] keys : loader.requiredOptions()) {
                 boolean found = false;
                 for (String key : keys) {
-                    if (options.contains(key.toLowerCase())) {
+                    if (options.contains(key.toLowerCase(Locale.ROOT))) {
                         found = true;
                         break;
                     }
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/globalindex/HybridSearchRanker.java
 
b/paimon-common/src/main/java/org/apache/paimon/globalindex/HybridSearchRanker.java
index e3c910aa4b..4f506f5d4e 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/globalindex/HybridSearchRanker.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/globalindex/HybridSearchRanker.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.PriorityQueue;
 
@@ -63,7 +64,7 @@ public class HybridSearchRanker {
         if (ranker == null || ranker.trim().isEmpty()) {
             return RRF_RANKER;
         }
-        String normalized = ranker.trim().toLowerCase();
+        String normalized = ranker.trim().toLowerCase(Locale.ROOT);
         if (!RRF_RANKER.equals(normalized)
                 && !WEIGHTED_SCORE_RANKER.equals(normalized)
                 && !MRR_RANKER.equals(normalized)) {
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/lookup/sort/db/LocalKvDb.java 
b/paimon-common/src/main/java/org/apache/paimon/lookup/sort/db/LocalKvDb.java
index bf2e5698f7..a0b8a7b8d6 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/lookup/sort/db/LocalKvDb.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/lookup/sort/db/LocalKvDb.java
@@ -46,6 +46,7 @@ import java.util.Comparator;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.PriorityQueue;
 import java.util.TreeMap;
@@ -946,7 +947,8 @@ public class LocalKvDb implements Closeable {
 
     private File newSstFile() {
         long sequence = fileSequence.getAndIncrement();
-        return new File(dataDirectory, String.format("sst-%s-%06d.db", uuid, 
sequence));
+        return new File(
+                dataDirectory, String.format(Locale.ROOT, "sst-%s-%06d.db", 
uuid, sequence));
     }
 
     private void ensureOpen() {
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/statistics/SimpleColStatsCollector.java
 
b/paimon-common/src/main/java/org/apache/paimon/statistics/SimpleColStatsCollector.java
index a928102044..c72bea6295 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/statistics/SimpleColStatsCollector.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/statistics/SimpleColStatsCollector.java
@@ -22,6 +22,7 @@ import org.apache.paimon.data.serializer.Serializer;
 import org.apache.paimon.format.SimpleColStats;
 
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.regex.Matcher;
 
 import static 
org.apache.paimon.statistics.TruncateSimpleColStatsCollector.TRUNCATE_PATTERN;
@@ -62,7 +63,7 @@ public interface SimpleColStatsCollector {
     }
 
     static Factory from(String option) {
-        String upper = option.toUpperCase();
+        String upper = option.toUpperCase(Locale.ROOT);
         switch (upper) {
             case "NONE":
                 return NoneSimpleColStatsCollector::new;
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/utils/BlobDescriptorUtils.java 
b/paimon-common/src/main/java/org/apache/paimon/utils/BlobDescriptorUtils.java
index 1cc1366bc8..ceb328053d 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/utils/BlobDescriptorUtils.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/utils/BlobDescriptorUtils.java
@@ -28,6 +28,7 @@ import javax.annotation.Nullable;
 import java.io.IOException;
 import java.net.URI;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
@@ -61,7 +62,7 @@ public class BlobDescriptorUtils {
     }
 
     private static String normalizeScheme(@Nullable String scheme) {
-        return scheme == null ? null : scheme.toLowerCase();
+        return scheme == null ? null : scheme.toLowerCase(Locale.ROOT);
     }
 
     /**
diff --git a/paimon-common/src/main/java/org/apache/paimon/utils/JNIUtils.java 
b/paimon-common/src/main/java/org/apache/paimon/utils/JNIUtils.java
index c9b4c657a4..eff716be3d 100644
--- a/paimon-common/src/main/java/org/apache/paimon/utils/JNIUtils.java
+++ b/paimon-common/src/main/java/org/apache/paimon/utils/JNIUtils.java
@@ -24,6 +24,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Locale;
 import java.util.logging.Logger;
 
 /**
@@ -37,7 +38,7 @@ public class JNIUtils {
     private static boolean inited = false;
 
     private static String osName() {
-        String osName = System.getProperty("os.name").toLowerCase().replace(' 
', '_');
+        String osName = 
System.getProperty("os.name").toLowerCase(Locale.ROOT).replace(' ', '_');
         if (osName.startsWith("win")) {
             return "win";
         } else {
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/utils/OperatingSystem.java 
b/paimon-common/src/main/java/org/apache/paimon/utils/OperatingSystem.java
index 9e923b3faa..3188def893 100644
--- a/paimon-common/src/main/java/org/apache/paimon/utils/OperatingSystem.java
+++ b/paimon-common/src/main/java/org/apache/paimon/utils/OperatingSystem.java
@@ -18,6 +18,8 @@
 
 package org.apache.paimon.utils;
 
+import java.util.Locale;
+
 /** An enumeration indicating the operating system that the JVM runs on. */
 public enum OperatingSystem {
     LINUX,
@@ -115,7 +117,7 @@ public enum OperatingSystem {
         if (osName.startsWith(FREEBSD_OS_PREFIX)) {
             return FREE_BSD;
         }
-        String osNameLowerCase = osName.toLowerCase();
+        String osNameLowerCase = osName.toLowerCase(Locale.ROOT);
         if (osNameLowerCase.contains(SOLARIS_OS_INFIX_1)
                 || osNameLowerCase.contains(SOLARIS_OS_INFIX_2)) {
             return SOLARIS;
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/format/FileFormatPrefixOptionsTest.java
 
b/paimon-common/src/test/java/org/apache/paimon/format/FileFormatPrefixOptionsTest.java
new file mode 100644
index 0000000000..23b6deda78
--- /dev/null
+++ 
b/paimon-common/src/test/java/org/apache/paimon/format/FileFormatPrefixOptionsTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.format;
+
+import org.apache.paimon.options.Options;
+import org.apache.paimon.predicate.Predicate;
+import org.apache.paimon.types.RowType;
+
+import org.junit.jupiter.api.Test;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+/** Tests for the format-prefixed option filtering in {@link FileFormat}. */
+class FileFormatPrefixOptionsTest {
+
+    /** U+0130, whose lower case under {@link Locale#ROOT} is the two 
characters below. */
+    private static final String DOTTED_CAPITAL_I = "İ";
+
+    private static final String LOWER_CASE_DOTTED_I = "i̇";
+
+    @Test
+    void prefixIsMatchedCaseInsensitively() {
+        Options options = new Options();
+        options.set("ORC.compression", "zstd");
+        options.set("avro.codec", "snappy");
+
+        Options prefixed = new 
TestFileFormat("orc").getIdentifierPrefixOptions(options);
+
+        assertThat(prefixed.toMap()).containsExactly(entry("orc.compression", 
"zstd"));
+    }
+
+    @Test
+    void anIdentifierThatLowerCasesLongerKeepsItsOptions() {
+        
assertThat(DOTTED_CAPITAL_I.toLowerCase(Locale.ROOT)).isEqualTo(LOWER_CASE_DOTTED_I);
+
+        Options options = new Options();
+        options.set(DOTTED_CAPITAL_I + ".compression", "zstd");
+
+        Options prefixed = new 
TestFileFormat(DOTTED_CAPITAL_I).getIdentifierPrefixOptions(options);
+
+        // slicing the key at the length of the lower-cased prefix would drop 
the "c"
+        assertThat(prefixed.toMap())
+                .containsExactly(entry(LOWER_CASE_DOTTED_I + ".compression", 
"zstd"));
+    }
+
+    @Test
+    void aKeyThatIsOnlyThePrefixYieldsAnEmptySuffix() {
+        Options options = new Options();
+        options.set(DOTTED_CAPITAL_I + ".", "zstd");
+
+        Options prefixed = new 
TestFileFormat(DOTTED_CAPITAL_I).getIdentifierPrefixOptions(options);
+
+        // this key is shorter than the lower-cased prefix, so slicing at its 
length overruns it
+        assertThat(prefixed.toMap()).containsExactly(entry(LOWER_CASE_DOTTED_I 
+ ".", "zstd"));
+    }
+
+    private static class TestFileFormat extends FileFormat {
+
+        private TestFileFormat(String formatIdentifier) {
+            super(formatIdentifier);
+        }
+
+        @Override
+        public FormatReaderFactory createReaderFactory(
+                RowType dataSchemaRowType,
+                RowType projectedRowType,
+                @Nullable List<Predicate> filters) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public FormatWriterFactory createWriterFactory(RowType type) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void validateDataFields(RowType rowType) {}
+    }
+}
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java 
b/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java
index c4cb9b95bc..c0bf33c597 100644
--- a/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java
+++ b/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.params.provider.ValueSource;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 import java.util.Random;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -451,6 +452,21 @@ class StringUtilsTest {
             String result = StringUtils.toLowerCaseIfNeed(input, 
caseSensitive);
             assertThat(result).isEqualTo(expected);
         }
+
+        @Test
+        void testToLowerCaseIfNeedIndependentOfDefaultLocale() {
+            Locale original = Locale.getDefault();
+            try {
+                // Turkish lowercases 'I' to a dotless glyph under its locale;
+                // identifier matching must stay locale-independent
+                Locale.setDefault(new Locale("tr", "TR"));
+                assertThat(StringUtils.toLowerCaseIfNeed("INDEX", 
false)).isEqualTo("index");
+                
assertThat(StringUtils.toLowerCase("INDEX")).isEqualTo("index");
+                
assertThat(StringUtils.toUpperCase("ıindex")).isEqualTo("IINDEX");
+            } finally {
+                Locale.setDefault(original);
+            }
+        }
     }
 
     @Nested
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java
index 916f63350c..98acf9fd8d 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java
@@ -62,6 +62,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -408,7 +409,7 @@ public class CatalogUtils {
 
     private static Table createGlobalSystemTable(String tableName, Catalog 
catalog)
             throws Catalog.TableNotExistException {
-        switch (tableName.toLowerCase()) {
+        switch (tableName.toLowerCase(Locale.ROOT)) {
             case ALL_TABLE_OPTIONS:
                 List<Table> tables = listAllTables(catalog);
                 Map<Identifier, Map<String, String>> allOptions = new 
HashMap<>();
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/disk/FileIOChannel.java 
b/paimon-core/src/main/java/org/apache/paimon/disk/FileIOChannel.java
index 4b72029ddd..8a3dd0098f 100644
--- a/paimon-core/src/main/java/org/apache/paimon/disk/FileIOChannel.java
+++ b/paimon-core/src/main/java/org/apache/paimon/disk/FileIOChannel.java
@@ -24,6 +24,7 @@ import org.apache.paimon.utils.StringUtils;
 import java.io.File;
 import java.io.IOException;
 import java.nio.channels.FileChannel;
+import java.util.Locale;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -163,7 +164,8 @@ public interface FileIOChannel {
 
         public FileIOChannel.ID next() {
             int bucketNum = GLOBAL_NUMBER.getAndIncrement() % paths.length;
-            String filename = String.format("%s.%06d.channel", namePrefix, 
(localCounter++));
+            String filename =
+                    String.format(Locale.ROOT, "%s.%06d.channel", namePrefix, 
(localCounter++));
             return new FileIOChannel.ID(new File(paths[bucketNum], filename), 
bucketNum);
         }
     }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergPathFactory.java 
b/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergPathFactory.java
index 9025dbe87a..da44d5ac46 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergPathFactory.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergPathFactory.java
@@ -25,6 +25,7 @@ import org.apache.paimon.utils.FileUtils;
 import org.apache.paimon.utils.PathFactory;
 
 import java.io.IOException;
+import java.util.Locale;
 import java.util.UUID;
 import java.util.stream.Stream;
 
@@ -65,7 +66,8 @@ public class IcebergPathFactory {
     }
 
     public Path toMetadataPath(long snapshotId) {
-        return new Path(metadataDirectory(), 
String.format("v%d.metadata.json", snapshotId));
+        return new Path(
+                metadataDirectory(), String.format(Locale.ROOT, 
"v%d.metadata.json", snapshotId));
     }
 
     public Path toMetadataPath(String metadataName) {
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/jdbc/DistributedLockDialectFactory.java
 
b/paimon-core/src/main/java/org/apache/paimon/jdbc/DistributedLockDialectFactory.java
index e0c167a4df..f324aa41e1 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/jdbc/DistributedLockDialectFactory.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/jdbc/DistributedLockDialectFactory.java
@@ -18,9 +18,11 @@
 
 package org.apache.paimon.jdbc;
 
+import java.util.Locale;
+
 class DistributedLockDialectFactory {
     static JdbcDistributedLockDialect create(String protocol) {
-        JdbcProtocol type = JdbcProtocol.valueOf(protocol.toUpperCase());
+        JdbcProtocol type = 
JdbcProtocol.valueOf(protocol.toUpperCase(Locale.ROOT));
         switch (type) {
             case SQLITE:
                 return new SqlLiteDistributedLockDialect();
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/lookup/local/LocalKvStateFactory.java
 
b/paimon-core/src/main/java/org/apache/paimon/lookup/local/LocalKvStateFactory.java
index b3041a988f..3461bb3df7 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/lookup/local/LocalKvStateFactory.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/lookup/local/LocalKvStateFactory.java
@@ -35,6 +35,7 @@ import java.io.File;
 import java.io.IOException;
 import java.time.Duration;
 import java.util.LinkedHashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.function.LongSupplier;
@@ -152,7 +153,7 @@ public class LocalKvStateFactory implements StateFactory {
         checkArgument(!databases.containsKey(name), "State '%s' already 
exists.", name);
 
         File stateDirectory =
-                new File(rootDirectory, String.format("state-%06d", 
databases.size()));
+                new File(rootDirectory, String.format(Locale.ROOT, 
"state-%06d", databases.size()));
         LocalKvDb db =
                 LocalKvDb.builder(stateDirectory)
                         .cacheManager(cacheManager)
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/ChainTableFileStoreTable.java
 
b/paimon-core/src/main/java/org/apache/paimon/table/ChainTableFileStoreTable.java
index dec16c5504..490940fe73 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/table/ChainTableFileStoreTable.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/ChainTableFileStoreTable.java
@@ -36,6 +36,7 @@ import org.apache.paimon.table.source.TableRead;
 import org.apache.paimon.types.RowType;
 
 import java.io.IOException;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -107,7 +108,7 @@ public class ChainTableFileStoreTable extends 
FallbackReadFileStoreTable {
                 }
                 return "from-timestamp";
             default:
-                return effectiveMode.name().toLowerCase().replace('_', '-');
+                return 
effectiveMode.name().toLowerCase(Locale.ROOT).replace('_', '-');
         }
     }
 
diff --git a/paimon-core/src/main/java/org/apache/paimon/table/FormatTable.java 
b/paimon-core/src/main/java/org/apache/paimon/table/FormatTable.java
index acb487e257..7f3ee12d6e 100644
--- a/paimon-core/src/main/java/org/apache/paimon/table/FormatTable.java
+++ b/paimon-core/src/main/java/org/apache/paimon/table/FormatTable.java
@@ -50,6 +50,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -104,7 +105,7 @@ public interface FormatTable extends Table {
     /** Parses a file format string to a corresponding {@link Format} enum 
constant. */
     static Format parseFormat(String fileFormat) {
         try {
-            return Format.valueOf(fileFormat.toUpperCase());
+            return Format.valueOf(fileFormat.toUpperCase(Locale.ROOT));
         } catch (IllegalArgumentException e) {
             throw new UnsupportedOperationException(
                     "Format table unsupported file format: "
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionVectorScan.java
 
b/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionVectorScan.java
index fdb57385ab..876f49d822 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionVectorScan.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionVectorScan.java
@@ -40,6 +40,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -311,7 +312,7 @@ public class DataEvolutionVectorScan implements VectorScan {
         if (value == null) {
             value = table.options().get(key);
         }
-        return value == null ? null : value.toLowerCase().trim();
+        return value == null ? null : value.toLowerCase(Locale.ROOT).trim();
     }
 
     private static boolean containsField(GlobalIndexMeta meta, int fieldId) {
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/system/SystemTableLoader.java
 
b/paimon-core/src/main/java/org/apache/paimon/table/system/SystemTableLoader.java
index 7767309468..c5ed1e2ecd 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/table/system/SystemTableLoader.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/system/SystemTableLoader.java
@@ -33,6 +33,7 @@ import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Function;
@@ -103,7 +104,7 @@ public class SystemTableLoader {
 
     @Nullable
     public static Table load(String type, FileStoreTable dataTable) {
-        String name = type.toLowerCase();
+        String name = type.toLowerCase(Locale.ROOT);
         if (PHYSICAL_METADATA_TABLES.contains(name) && 
dataTable.coreOptions().queryAuthEnabled()) {
             throw new UnsupportedOperationException(
                     String.format(
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/utils/PartitionPathUtils.java 
b/paimon-core/src/main/java/org/apache/paimon/utils/PartitionPathUtils.java
index 9e979a98a9..aec2b21aae 100644
--- a/paimon-core/src/main/java/org/apache/paimon/utils/PartitionPathUtils.java
+++ b/paimon-core/src/main/java/org/apache/paimon/utils/PartitionPathUtils.java
@@ -42,6 +42,7 @@ import java.util.BitSet;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
@@ -302,7 +303,7 @@ public class PartitionPathUtils {
         if (c < 16) {
             sb.append('0');
         }
-        sb.append(Integer.toHexString(c).toUpperCase());
+        sb.append(Integer.toHexString(c).toUpperCase(Locale.ROOT));
     }
 
     public static String unescapePathName(String path) {
diff --git 
a/paimon-docs/src/main/java/org/apache/paimon/docs/configuration/ConfigOptionsDocGenerator.java
 
b/paimon-docs/src/main/java/org/apache/paimon/docs/configuration/ConfigOptionsDocGenerator.java
index ebb167cbac..28e38b0507 100644
--- 
a/paimon-docs/src/main/java/org/apache/paimon/docs/configuration/ConfigOptionsDocGenerator.java
+++ 
b/paimon-docs/src/main/java/org/apache/paimon/docs/configuration/ConfigOptionsDocGenerator.java
@@ -55,6 +55,7 @@ import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.regex.Matcher;
@@ -263,7 +264,7 @@ public class ConfigOptionsDocGenerator {
 
     @VisibleForTesting
     static String toSnakeCase(String name) {
-        return name.replaceAll("(.)([A-Z][a-z])", "$1_$2").toLowerCase();
+        return name.replaceAll("(.)([A-Z][a-z])", 
"$1_$2").toLowerCase(Locale.ROOT);
     }
 
     @VisibleForTesting
diff --git 
a/paimon-filesystems/paimon-cosn-impl/src/main/java/org/apache/paimon/cosn/COSNFileIO.java
 
b/paimon-filesystems/paimon-cosn-impl/src/main/java/org/apache/paimon/cosn/COSNFileIO.java
index 0f0096751d..ddec6d38e0 100644
--- 
a/paimon-filesystems/paimon-cosn-impl/src/main/java/org/apache/paimon/cosn/COSNFileIO.java
+++ 
b/paimon-filesystems/paimon-cosn-impl/src/main/java/org/apache/paimon/cosn/COSNFileIO.java
@@ -33,6 +33,7 @@ import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.net.URI;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
@@ -52,8 +53,10 @@ public class COSNFileIO extends HadoopCompliantFileIO {
     private static final Map<String, String> CASE_SENSITIVE_KEYS =
             new HashMap<String, String>() {
                 {
-                    put(COSN_USER_INFO_KEY_ID.toLowerCase(), 
COSN_USER_INFO_KEY_ID);
-                    put(COSN_USER_INFO_KEY_SECRET.toLowerCase(), 
COSN_USER_INFO_KEY_SECRET);
+                    put(COSN_USER_INFO_KEY_ID.toLowerCase(Locale.ROOT), 
COSN_USER_INFO_KEY_ID);
+                    put(
+                            COSN_USER_INFO_KEY_SECRET.toLowerCase(Locale.ROOT),
+                            COSN_USER_INFO_KEY_SECRET);
                 }
             };
     /**
@@ -77,8 +80,8 @@ public class COSNFileIO extends HadoopCompliantFileIO {
             for (String prefix : CONFIG_PREFIXES) {
                 if (key.startsWith(prefix)) {
                     String value = context.options().get(key);
-                    if (CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase())) {
-                        key = CASE_SENSITIVE_KEYS.get(key.toLowerCase());
+                    if 
(CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase(Locale.ROOT))) {
+                        key = 
CASE_SENSITIVE_KEYS.get(key.toLowerCase(Locale.ROOT));
                     }
                     hadoopOptions.set(key, value);
                     LOG.debug(
diff --git 
a/paimon-filesystems/paimon-jindo/src/main/java/org/apache/paimon/jindo/JindoFileIO.java
 
b/paimon-filesystems/paimon-jindo/src/main/java/org/apache/paimon/jindo/JindoFileIO.java
index 31e0d440d9..e5e2ede687 100644
--- 
a/paimon-filesystems/paimon-jindo/src/main/java/org/apache/paimon/jindo/JindoFileIO.java
+++ 
b/paimon-filesystems/paimon-jindo/src/main/java/org/apache/paimon/jindo/JindoFileIO.java
@@ -46,6 +46,7 @@ import java.io.UncheckedIOException;
 import java.net.URI;
 import java.time.Duration;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
@@ -79,9 +80,9 @@ public class JindoFileIO extends HadoopCompliantFileIO 
implements HadoopOptionsP
     private static final Map<String, String> CASE_SENSITIVE_KEYS =
             new HashMap<String, String>() {
                 {
-                    put(OSS_ACCESS_KEY_ID.toLowerCase(), OSS_ACCESS_KEY_ID);
-                    put(OSS_ACCESS_KEY_SECRET.toLowerCase(), 
OSS_ACCESS_KEY_SECRET);
-                    put(OSS_SECURITY_TOKEN.toLowerCase(), OSS_SECURITY_TOKEN);
+                    put(OSS_ACCESS_KEY_ID.toLowerCase(Locale.ROOT), 
OSS_ACCESS_KEY_ID);
+                    put(OSS_ACCESS_KEY_SECRET.toLowerCase(Locale.ROOT), 
OSS_ACCESS_KEY_SECRET);
+                    put(OSS_SECURITY_TOKEN.toLowerCase(Locale.ROOT), 
OSS_SECURITY_TOKEN);
                 }
             };
 
@@ -118,8 +119,8 @@ public class JindoFileIO extends HadoopCompliantFileIO 
implements HadoopOptionsP
             for (String prefix : CONFIG_PREFIXES) {
                 if (key.startsWith(prefix)) {
                     String value = context.options().get(key);
-                    if (CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase())) {
-                        key = CASE_SENSITIVE_KEYS.get(key.toLowerCase());
+                    if 
(CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase(Locale.ROOT))) {
+                        key = 
CASE_SENSITIVE_KEYS.get(key.toLowerCase(Locale.ROOT));
                     }
                     hadoopOptions.set(key, value);
 
diff --git 
a/paimon-filesystems/paimon-obs-impl/src/main/java/org/apache/paimon/obs/OBSFileIO.java
 
b/paimon-filesystems/paimon-obs-impl/src/main/java/org/apache/paimon/obs/OBSFileIO.java
index 4f425ca590..408bcc0a7b 100644
--- 
a/paimon-filesystems/paimon-obs-impl/src/main/java/org/apache/paimon/obs/OBSFileIO.java
+++ 
b/paimon-filesystems/paimon-obs-impl/src/main/java/org/apache/paimon/obs/OBSFileIO.java
@@ -33,6 +33,7 @@ import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.net.URI;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
@@ -60,9 +61,9 @@ public class OBSFileIO extends HadoopCompliantFileIO {
     private static final Map<String, String> CASE_SENSITIVE_KEYS =
             new HashMap<String, String>() {
                 {
-                    put(OBS_ACCESS_KEY_ID.toLowerCase(), OBS_ACCESS_KEY_ID);
-                    put(OBS_ACCESS_KEY_SECRET.toLowerCase(), 
OBS_ACCESS_KEY_SECRET);
-                    put(OBS_SESSION_TOKEN.toLowerCase(), OBS_SESSION_TOKEN);
+                    put(OBS_ACCESS_KEY_ID.toLowerCase(Locale.ROOT), 
OBS_ACCESS_KEY_ID);
+                    put(OBS_ACCESS_KEY_SECRET.toLowerCase(Locale.ROOT), 
OBS_ACCESS_KEY_SECRET);
+                    put(OBS_SESSION_TOKEN.toLowerCase(Locale.ROOT), 
OBS_SESSION_TOKEN);
                 }
             };
 
@@ -92,8 +93,8 @@ public class OBSFileIO extends HadoopCompliantFileIO {
             for (String prefix : CONFIG_PREFIXES) {
                 if (key.startsWith(prefix)) {
                     String value = context.options().get(key);
-                    if (CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase())) {
-                        key = CASE_SENSITIVE_KEYS.get(key.toLowerCase());
+                    if 
(CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase(Locale.ROOT))) {
+                        key = 
CASE_SENSITIVE_KEYS.get(key.toLowerCase(Locale.ROOT));
                     }
                     hadoopOptions.set(key, value);
 
diff --git 
a/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
 
b/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
index 5a3b48a5c5..3249cbfcef 100644
--- 
a/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
+++ 
b/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
@@ -58,6 +58,7 @@ import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
@@ -115,9 +116,9 @@ public class OSSFileIO extends HadoopCompliantFileIO 
implements HadoopOptionsPro
     private static final Map<String, String> CASE_SENSITIVE_KEYS =
             new HashMap<String, String>() {
                 {
-                    put(OSS_ACCESS_KEY_ID.toLowerCase(), OSS_ACCESS_KEY_ID);
-                    put(OSS_ACCESS_KEY_SECRET.toLowerCase(), 
OSS_ACCESS_KEY_SECRET);
-                    put(OSS_SECURITY_TOKEN.toLowerCase(), OSS_SECURITY_TOKEN);
+                    put(OSS_ACCESS_KEY_ID.toLowerCase(Locale.ROOT), 
OSS_ACCESS_KEY_ID);
+                    put(OSS_ACCESS_KEY_SECRET.toLowerCase(Locale.ROOT), 
OSS_ACCESS_KEY_SECRET);
+                    put(OSS_SECURITY_TOKEN.toLowerCase(Locale.ROOT), 
OSS_SECURITY_TOKEN);
                 }
             };
 
@@ -147,8 +148,8 @@ public class OSSFileIO extends HadoopCompliantFileIO 
implements HadoopOptionsPro
             for (String prefix : CONFIG_PREFIXES) {
                 if (key.startsWith(prefix)) {
                     String value = context.options().get(key);
-                    if (CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase())) {
-                        key = CASE_SENSITIVE_KEYS.get(key.toLowerCase());
+                    if 
(CASE_SENSITIVE_KEYS.containsKey(key.toLowerCase(Locale.ROOT))) {
+                        key = 
CASE_SENSITIVE_KEYS.get(key.toLowerCase(Locale.ROOT));
                     }
                     hadoopOptions.set(key, value);
 
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/CdcActionCommonUtils.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/CdcActionCommonUtils.java
index e7228eb202..54b7c8492a 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/CdcActionCommonUtils.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/CdcActionCommonUtils.java
@@ -36,6 +36,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
@@ -156,7 +157,7 @@ public class CdcActionCommonUtils {
     public static List<String> listCaseConvert(List<String> origin, boolean 
caseSensitive) {
         return caseSensitive
                 ? origin
-                : 
origin.stream().map(String::toLowerCase).collect(Collectors.toList());
+                : origin.stream().map(s -> 
s.toLowerCase(Locale.ROOT)).collect(Collectors.toList());
     }
 
     public static Schema buildPaimonSchema(
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/Expression.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/Expression.java
index 087fe15e67..9c82b0faa4 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/Expression.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/Expression.java
@@ -37,6 +37,7 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -191,11 +192,11 @@ public interface Expression extends Serializable {
                 Arrays.stream(ExpressionFunction.values())
                         .collect(
                                 Collectors.toMap(
-                                        value -> value.name().toLowerCase(),
+                                        value -> 
value.name().toLowerCase(Locale.ROOT),
                                         ExpressionFunction::getCreator));
 
         public static ExpressionCreator creator(String exprName) {
-            return EXPRESSION_FUNCTIONS.get(exprName.toLowerCase());
+            return EXPRESSION_FUNCTIONS.get(exprName.toLowerCase(Locale.ROOT));
         }
     }
 
@@ -253,7 +254,7 @@ public interface Expression extends Serializable {
             String exprName,
             String... args) {
 
-        ExpressionCreator function = 
ExpressionFunction.creator(exprName.toLowerCase());
+        ExpressionCreator function = 
ExpressionFunction.creator(exprName.toLowerCase(Locale.ROOT));
         if (function == null) {
             throw new UnsupportedOperationException(
                     String.format(
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/SyncDatabaseActionBase.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/SyncDatabaseActionBase.java
index 7300d5d79a..7439c2739e 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/SyncDatabaseActionBase.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/SyncDatabaseActionBase.java
@@ -39,6 +39,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.regex.Pattern;
 
@@ -113,7 +114,10 @@ public abstract class SyncDatabaseActionBase extends 
SynchronizationActionBase {
                     dbPrefix.entrySet().stream()
                             .collect(
                                     HashMap::new,
-                                    (m, e) -> m.put(e.getKey().toLowerCase(), 
e.getValue()),
+                                    (m, e) ->
+                                            m.put(
+                                                    
e.getKey().toLowerCase(Locale.ROOT),
+                                                    e.getValue()),
                                     HashMap::putAll);
         }
         return this;
@@ -125,7 +129,10 @@ public abstract class SyncDatabaseActionBase extends 
SynchronizationActionBase {
                     dbSuffix.entrySet().stream()
                             .collect(
                                     HashMap::new,
-                                    (m, e) -> m.put(e.getKey().toLowerCase(), 
e.getValue()),
+                                    (m, e) ->
+                                            m.put(
+                                                    
e.getKey().toLowerCase(Locale.ROOT),
+                                                    e.getValue()),
                                     HashMap::putAll);
         }
         return this;
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TableNameConverter.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TableNameConverter.java
index 7dd63ed227..44cd51be83 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TableNameConverter.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TableNameConverter.java
@@ -22,6 +22,7 @@ import org.apache.paimon.catalog.Identifier;
 
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
 import static org.apache.paimon.utils.StringUtils.toLowerCaseIfNeed;
@@ -78,8 +79,8 @@ public class TableNameConverter implements Serializable {
 
     public String convert(String originDbName, String originTblName) {
         // top priority: table mapping
-        if (tableMapping.containsKey(originTblName.toLowerCase())) {
-            String mappedName = tableMapping.get(originTblName.toLowerCase());
+        if (tableMapping.containsKey(originTblName.toLowerCase(Locale.ROOT))) {
+            String mappedName = 
tableMapping.get(originTblName.toLowerCase(Locale.ROOT));
             return toLowerCaseIfNeed(mappedName, caseSensitive);
         }
 
@@ -87,11 +88,11 @@ public class TableNameConverter implements Serializable {
         String tblSuffix = suffix;
 
         // second priority: prefix and postfix specified by db
-        if (dbPrefix.containsKey(originDbName.toLowerCase())) {
-            tblPrefix = dbPrefix.get(originDbName.toLowerCase());
+        if (dbPrefix.containsKey(originDbName.toLowerCase(Locale.ROOT))) {
+            tblPrefix = dbPrefix.get(originDbName.toLowerCase(Locale.ROOT));
         }
-        if (dbSuffix.containsKey(originDbName.toLowerCase())) {
-            tblSuffix = dbSuffix.get(originDbName.toLowerCase());
+        if (dbSuffix.containsKey(originDbName.toLowerCase(Locale.ROOT))) {
+            tblSuffix = dbSuffix.get(originDbName.toLowerCase(Locale.ROOT));
         }
 
         // third priority: normal prefix and suffix
@@ -117,7 +118,7 @@ public class TableNameConverter implements Serializable {
         }
 
         for (String key : map.keySet()) {
-            lowerKeyMap.put(key.toLowerCase(), map.get(key));
+            lowerKeyMap.put(key.toLowerCase(Locale.ROOT), map.get(key));
         }
 
         return lowerKeyMap;
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TypeMapping.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TypeMapping.java
index 499c3823b9..ce10ae6dfc 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TypeMapping.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/TypeMapping.java
@@ -21,6 +21,7 @@ package org.apache.paimon.flink.action.cdc;
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
@@ -49,7 +50,7 @@ public class TypeMapping implements Serializable {
         Set<TypeMappingMode> typeMappingModes =
                 Arrays.stream(rawOptions)
                         .map(String::trim)
-                        .map(String::toLowerCase)
+                        .map(s -> s.toLowerCase(Locale.ROOT))
                         .map(TypeMappingMode::mode)
                         .collect(Collectors.toSet());
         return new TypeMapping(typeMappingModes);
@@ -96,7 +97,7 @@ public class TypeMapping implements Serializable {
         }
 
         public String configString() {
-            return name().toLowerCase().replace("_", "-");
+            return name().toLowerCase(Locale.ROOT).replace("_", "-");
         }
     }
 }
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/format/DataFormatFactory.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/format/DataFormatFactory.java
index df1e92d907..0893c00124 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/format/DataFormatFactory.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/format/DataFormatFactory.java
@@ -22,13 +22,15 @@ import org.apache.paimon.factories.Factory;
 import org.apache.paimon.factories.FactoryException;
 import org.apache.paimon.factories.FactoryUtil;
 
+import java.util.Locale;
+
 /** Factory to create {@link DataFormat}. */
 public interface DataFormatFactory extends Factory {
 
     DataFormat create();
 
     static DataFormat createDataFormat(String format) {
-        String identifier = format.toLowerCase();
+        String identifier = format.toLowerCase(Locale.ROOT);
         DataFormatFactory dataFormatFactory;
         try {
             dataFormatFactory =
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/kafka/KafkaActionUtils.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/kafka/KafkaActionUtils.java
index c34c34038d..8f85335edd 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/kafka/KafkaActionUtils.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/kafka/KafkaActionUtils.java
@@ -176,7 +176,7 @@ public class KafkaActionUtils {
                                                 offsetResetConfig,
                                                 
Arrays.stream(OffsetResetStrategy.values())
                                                         .map(Enum::name)
-                                                        
.map(String::toLowerCase)
+                                                        .map(s -> 
s.toLowerCase(Locale.ROOT))
                                                         
.collect(Collectors.joining(",")))));
     }
 
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBActionUtils.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBActionUtils.java
index ddc69a180c..0fa299811f 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBActionUtils.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBActionUtils.java
@@ -33,6 +33,7 @@ import org.apache.flink.configuration.Configuration;
 import org.apache.kafka.connect.json.JsonConverterConfig;
 
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -118,7 +119,7 @@ public class MongoDBActionUtils {
                 .collectionList(tableList);
 
         String startupMode = 
mongodbConfig.get(SourceOptions.SCAN_STARTUP_MODE);
-        switch (startupMode.toLowerCase()) {
+        switch (startupMode.toLowerCase(Locale.ROOT)) {
             case INITIAL_MODE:
                 sourceBuilder.startupOptions(StartupOptions.initial());
                 break;
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBSchemaUtils.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBSchemaUtils.java
index 9dbb6eef7d..0c35718898 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBSchemaUtils.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/MongoDBSchemaUtils.java
@@ -38,6 +38,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
 
 import static 
org.apache.flink.cdc.connectors.mongodb.internal.MongoDBEnvelope.encodeValue;
@@ -153,7 +154,8 @@ public class MongoDBSchemaUtils {
     }
 
     private static SchemaAcquisitionMode getModeFromConfig(Configuration 
mongodbConfig) {
-        return 
SchemaAcquisitionMode.valueOf(mongodbConfig.get(START_MODE).toUpperCase());
+        return SchemaAcquisitionMode.valueOf(
+                mongodbConfig.get(START_MODE).toUpperCase(Locale.ROOT));
     }
 
     private static List<String> getColumnNames(Document document) {
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/strategy/MongoVersionStrategy.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/strategy/MongoVersionStrategy.java
index 0a72f71160..f0ad32eac2 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/strategy/MongoVersionStrategy.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mongodb/strategy/MongoVersionStrategy.java
@@ -35,6 +35,7 @@ import org.apache.flink.configuration.Configuration;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -86,7 +87,8 @@ public interface MongoVersionStrategy {
             return null;
         }
         SchemaAcquisitionMode mode =
-                
SchemaAcquisitionMode.valueOf(mongodbConfig.get(START_MODE).toUpperCase());
+                SchemaAcquisitionMode.valueOf(
+                        
mongodbConfig.get(START_MODE).toUpperCase(Locale.ROOT));
         ObjectNode objectNode =
                 JsonSerdeUtil.asSpecificNodeType(jsonNode.asText(), 
ObjectNode.class);
         JsonNode idNode = objectNode.get(ID_FIELD);
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mysql/MySqlTypeUtils.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mysql/MySqlTypeUtils.java
index 989236d8c8..efb2367a8e 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mysql/MySqlTypeUtils.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/mysql/MySqlTypeUtils.java
@@ -37,6 +37,7 @@ import javax.annotation.Nullable;
 
 import java.nio.ByteBuffer;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -153,8 +154,8 @@ public class MySqlTypeUtils {
         if (leftBracketIndex != -1) {
             int rightBracketIndex = typeName.indexOf(RIGHT_BRACKETS);
             shortType =
-                    typeName.substring(0, 
leftBracketIndex).trim().toUpperCase()
-                            + typeName.substring(rightBracketIndex + 
1).toUpperCase();
+                    typeName.substring(0, 
leftBracketIndex).trim().toUpperCase(Locale.ROOT)
+                            + typeName.substring(rightBracketIndex + 
1).toUpperCase(Locale.ROOT);
 
             String insideBrackets =
                     typeName.substring(leftBracketIndex + 1, 
rightBracketIndex).trim();
@@ -167,7 +168,7 @@ public class MySqlTypeUtils {
                 length = Integer.parseInt(insideBrackets);
             }
         } else {
-            shortType = typeName.toUpperCase();
+            shortType = typeName.toUpperCase(Locale.ROOT);
             if (isDecimalType(shortType)) {
                 // when missing precision and scale of the decimal, we
                 // use the max precision and scale to avoid parse error
@@ -187,7 +188,7 @@ public class MySqlTypeUtils {
             return DataTypes.STRING();
         }
 
-        switch (type.toUpperCase()) {
+        switch (type.toUpperCase(Locale.ROOT)) {
             case BIT:
                 if (length == null || length == 1) {
                     return DataTypes.BOOLEAN();
@@ -335,7 +336,7 @@ public class MySqlTypeUtils {
     }
 
     public static boolean isGeoType(String type) {
-        switch (type.toUpperCase()) {
+        switch (type.toUpperCase(Locale.ROOT)) {
             case GEOMETRY:
             case POINT:
             case LINESTRING:
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/postgres/PostgresTypeUtils.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/postgres/PostgresTypeUtils.java
index 7fae4c4327..9ec33e498a 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/postgres/PostgresTypeUtils.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/action/cdc/postgres/PostgresTypeUtils.java
@@ -26,6 +26,8 @@ import org.apache.paimon.types.DecimalType;
 
 import javax.annotation.Nullable;
 
+import java.util.Locale;
+
 import static 
org.apache.paimon.flink.action.cdc.TypeMapping.TypeMappingMode.TO_STRING;
 
 /** Converts from Postgres type to {@link DataType}. */
@@ -83,7 +85,7 @@ public class PostgresTypeUtils {
         }
         precision = precision == null ? 0 : precision;
         scale = scale == null ? 0 : scale;
-        switch (typeName.toLowerCase()) {
+        switch (typeName.toLowerCase(Locale.ROOT)) {
             case PG_BIT:
             case PG_VARBIT:
                 if (precision <= 1) {
diff --git 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/sink/cdc/CdcRecord.java
 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/sink/cdc/CdcRecord.java
index b23d0d6f06..3093ebbfb5 100644
--- 
a/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/sink/cdc/CdcRecord.java
+++ 
b/paimon-flink/paimon-flink-cdc/src/main/java/org/apache/paimon/flink/sink/cdc/CdcRecord.java
@@ -24,6 +24,7 @@ import org.apache.paimon.types.RowKind;
 import java.io.Serializable;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
@@ -58,7 +59,10 @@ public class CdcRecord implements Serializable {
     public CdcRecord fieldNameLowerCase() {
         Map<String, String> newData = new HashMap<>();
         for (Map.Entry<String, String> entry : data.entrySet()) {
-            newData.put(entry.getKey().toLowerCase(), entry.getValue());
+            // Locale.ROOT: must match the schema-side toLowerCaseIfNeed 
conversion;
+            // a Turkish default locale would lowercase 'I' to a dotless glyph 
and
+            // silently null out the column on the record-schema join
+            newData.put(entry.getKey().toLowerCase(Locale.ROOT), 
entry.getValue());
         }
         return new CdcRecord(kind, newData);
     }
diff --git 
a/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/action/cdc/TurkishLocaleCaseFoldingTest.java
 
b/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/action/cdc/TurkishLocaleCaseFoldingTest.java
new file mode 100644
index 0000000000..2ff3505a03
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/action/cdc/TurkishLocaleCaseFoldingTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.flink.action.cdc;
+
+import org.apache.paimon.schema.Schema;
+import org.apache.paimon.types.DataTypes;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The CDC action layer case-folds identifiers and option values before 
matching them. {@link
+ * CdcActionCommonUtils#buildPaimonSchema} does it through separate helpers 
for field names and for
+ * key lists, and {@link TypeMapping#parse} does it for {@code --type-mapping} 
values. Under a
+ * Turkish default locale 'I' lowercases to a dotless glyph, so every one of 
those conversions has
+ * to pin {@link Locale#ROOT}: otherwise a key list holds a name no field has, 
and an option spelled
+ * in upper case stops matching any mode.
+ */
+class TurkishLocaleCaseFoldingTest {
+
+    private Locale original;
+
+    @BeforeEach
+    void setUp() {
+        original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+    }
+
+    @AfterEach
+    void tearDown() {
+        Locale.setDefault(original);
+    }
+
+    @Test
+    void primaryKeyInferredFromSourceSchemaNamesTheField() {
+        Schema source = Schema.newBuilder().column("ID", 
DataTypes.INT()).primaryKey("ID").build();
+
+        Schema result = build(Collections.emptyList(), 
Collections.emptyList(), source, true, true);
+
+        assertThat(result.fields().get(0).name()).isEqualTo("id");
+        assertThat(result.primaryKeys()).containsExactly("id");
+    }
+
+    @Test
+    void specifiedPrimaryKeyNamesTheField() {
+        Schema source = Schema.newBuilder().column("ID", 
DataTypes.INT()).build();
+
+        Schema result =
+                build(
+                        Collections.emptyList(),
+                        Collections.singletonList("ID"),
+                        source,
+                        false,
+                        false);
+
+        assertThat(result.primaryKeys()).containsExactly("id");
+    }
+
+    @Test
+    void specifiedPrimaryKeyPassesStrictChecking() {
+        Schema source = Schema.newBuilder().column("ID", 
DataTypes.INT()).build();
+
+        Schema result =
+                build(
+                        Collections.emptyList(),
+                        Collections.singletonList("ID"),
+                        source,
+                        true,
+                        false);
+
+        assertThat(result.primaryKeys()).containsExactly("id");
+    }
+
+    @Test
+    void specifiedPartitionKeySurvivesNonStrictChecking() {
+        Schema source =
+                Schema.newBuilder()
+                        .column("id", DataTypes.INT())
+                        .column("CITY", DataTypes.STRING())
+                        .build();
+
+        Schema result =
+                build(
+                        Collections.singletonList("CITY"),
+                        Collections.emptyList(),
+                        source,
+                        false,
+                        false);
+
+        assertThat(result.partitionKeys()).containsExactly("city");
+    }
+
+    @Test
+    void upperCaseTypeMappingOptionStillMatchesItsMode() {
+        TypeMapping mapping = TypeMapping.parse(new String[] 
{"TINYINT1-NOT-BOOL"});
+
+        
assertThat(mapping.containsMode(TypeMapping.TypeMappingMode.TINYINT1_NOT_BOOL)).isTrue();
+    }
+
+    private static Schema build(
+            List<String> specifiedPartitionKeys,
+            List<String> specifiedPrimaryKeys,
+            Schema sourceSchema,
+            boolean strictlyCheckSpecified,
+            boolean syncPKeysFromSourceSchema) {
+        return CdcActionCommonUtils.buildPaimonSchema(
+                "T",
+                specifiedPartitionKeys,
+                specifiedPrimaryKeys,
+                Collections.emptyList(),
+                Collections.emptyMap(),
+                sourceSchema,
+                new CdcMetadataConverter[0],
+                false,
+                strictlyCheckSpecified,
+                false,
+                syncPKeysFromSourceSchema);
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/action/cdc/mysql/TurkishLocaleTypeNameTest.java
 
b/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/action/cdc/mysql/TurkishLocaleTypeNameTest.java
new file mode 100644
index 0000000000..911d27467a
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/action/cdc/mysql/TurkishLocaleTypeNameTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.flink.action.cdc.mysql;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * A source type name is case-folded before it is matched against the names 
this class knows. Under
+ * a Turkish default locale 'i' maps to a dotted capital, so those conversions 
must pin {@link
+ * Locale#ROOT} or a type whose name contains an 'i' stops being recognized.
+ */
+class TurkishLocaleTypeNameTest {
+
+    private Locale original;
+
+    @BeforeEach
+    void setUp() {
+        original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+    }
+
+    @AfterEach
+    void tearDown() {
+        Locale.setDefault(original);
+    }
+
+    @Test
+    void lowerCaseTypeNameKeepsItsShortType() {
+        // a locale-sensitive uppercase turns "int" into "İNT", which no case 
arm names
+        assertThat(MySqlTypeUtils.getTypeInfo("int").f0).isEqualTo("INT");
+    }
+
+    @Test
+    void lowerCaseGeoTypeIsStillRecognized() {
+        assertThat(MySqlTypeUtils.isGeoType("point")).isTrue();
+        assertThat(MySqlTypeUtils.isGeoType("linestring")).isTrue();
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/sink/cdc/CdcRecordTest.java
 
b/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/sink/cdc/CdcRecordTest.java
new file mode 100644
index 0000000000..eadbe0fc36
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-cdc/src/test/java/org/apache/paimon/flink/sink/cdc/CdcRecordTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.flink.sink.cdc;
+
+import org.apache.paimon.types.RowKind;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Test for {@link CdcRecord}. */
+class CdcRecordTest {
+
+    @Test
+    void fieldNameLowerCaseIndependentOfDefaultLocale() {
+        Locale original = Locale.getDefault();
+        try {
+            // Turkish lowercases 'I' to a dotless glyph under its locale; the 
record-side
+            // keys must match the schema-side Locale.ROOT conversion or the 
column join
+            // silently nulls out
+            Locale.setDefault(new Locale("tr", "TR"));
+            Map<String, String> data = new HashMap<>();
+            data.put("INDEX", "v");
+            CdcRecord record = new CdcRecord(RowKind.INSERT, data);
+
+            CdcRecord converted = record.fieldNameLowerCase();
+
+            assertThat(converted.data()).containsEntry("index", 
"v").doesNotContainKey("ındex");
+        } finally {
+            Locale.setDefault(original);
+        }
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FormatCatalogTable.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FormatCatalogTable.java
index 5dbce5f0a4..fa0322090d 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FormatCatalogTable.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FormatCatalogTable.java
@@ -29,6 +29,7 @@ import org.apache.flink.table.types.logical.RowType;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -88,7 +89,7 @@ public class FormatCatalogTable implements CatalogTable {
     public Map<String, String> getOptions() {
         if (cachedOptions == null) {
             cachedOptions = new HashMap<>();
-            String format = table.format().name().toLowerCase();
+            String format = table.format().name().toLowerCase(Locale.ROOT);
             Map<String, String> options = table.options();
             options.forEach(
                     (k, v) -> {
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/ActionFactory.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/ActionFactory.java
index 4e71b14d25..1101bdc5b7 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/ActionFactory.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/ActionFactory.java
@@ -31,6 +31,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -71,7 +72,7 @@ public interface ActionFactory extends Factory {
 
     static Optional<Action> createAction(String[] args) {
         // to be compatible with old usage
-        String action = args[0].toLowerCase().replaceAll("-", "_");
+        String action = args[0].toLowerCase(Locale.ROOT).replaceAll("-", "_");
         String[] actionArgs = Arrays.copyOfRange(args, 1, args.length);
         ActionFactory actionFactory;
         try {
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CloneAction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CloneAction.java
index 4ee87710e6..8b34419435 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CloneAction.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CloneAction.java
@@ -29,6 +29,7 @@ import org.apache.paimon.utils.StringUtils;
 import javax.annotation.Nullable;
 
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 /** Clone source table to target table. */
@@ -104,7 +105,7 @@ public class CloneAction extends ActionBase {
         this.preferFileFormat =
                 StringUtils.isNullOrWhitespaceOnly(preferFileFormat)
                         ? preferFileFormat
-                        : preferFileFormat.toLowerCase();
+                        : preferFileFormat.toLowerCase(Locale.ROOT);
         this.cloneFrom = cloneFrom;
         this.metaOnly = metaOnly;
         this.cloneIfExists = cloneIfExists;
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/MultiTablesSinkMode.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/MultiTablesSinkMode.java
index d5c5141995..d5c0d06be2 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/MultiTablesSinkMode.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/MultiTablesSinkMode.java
@@ -21,6 +21,7 @@ package org.apache.paimon.flink.action;
 import javax.annotation.Nullable;
 
 import java.io.Serializable;
+import java.util.Locale;
 
 /**
  * There are two modes for database sink.
@@ -40,7 +41,7 @@ public enum MultiTablesSinkMode implements Serializable {
             return DIVIDED;
         }
 
-        switch (mode.toLowerCase()) {
+        switch (mode.toLowerCase(Locale.ROOT)) {
             case "divided":
                 return DIVIDED;
             case "combined":
@@ -51,6 +52,6 @@ public enum MultiTablesSinkMode implements Serializable {
     }
 
     public String configString() {
-        return name().toLowerCase().replace("_", "-");
+        return name().toLowerCase(Locale.ROOT).replace("_", "-");
     }
 }
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/clone/CloneFileFormatUtils.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/clone/CloneFileFormatUtils.java
index b1c73fce7d..88fbd11fba 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/clone/CloneFileFormatUtils.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/clone/CloneFileFormatUtils.java
@@ -21,6 +21,8 @@ package org.apache.paimon.flink.clone;
 import org.apache.paimon.flink.action.CloneAction;
 import org.apache.paimon.utils.StringUtils;
 
+import java.util.Locale;
+
 /** Utils for file format in {@link CloneAction}. */
 public class CloneFileFormatUtils {
 
@@ -28,7 +30,7 @@ public class CloneFileFormatUtils {
         if (StringUtils.isNullOrWhitespaceOnly(fileFormat)) {
             return;
         }
-        String fileFormatLower = fileFormat.toLowerCase();
+        String fileFormatLower = fileFormat.toLowerCase(Locale.ROOT);
         String[] supportedFileFormat = new String[] {"parquet", "orc", "avro"};
         for (String supportedFormat : supportedFileFormat) {
             if (fileFormatLower.equals(supportedFormat)) {
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/lookup/PartitionLoader.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/lookup/PartitionLoader.java
index 49d236a693..688321e31f 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/lookup/PartitionLoader.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/lookup/PartitionLoader.java
@@ -34,6 +34,7 @@ import java.io.Serializable;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /** Specify partitions for lookup tables. */
 public abstract class PartitionLoader implements Serializable {
@@ -95,7 +96,7 @@ public abstract class PartitionLoader implements Serializable 
{
                 FlinkConnectorOptions.SCAN_PARTITIONS.key());
 
         int maxPartitionNum = -1;
-        switch (scanPartitions.toLowerCase()) {
+        switch (scanPartitions.toLowerCase(Locale.ROOT)) {
             case MAX_PT:
                 maxPartitionNum = 1;
                 break;
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateGlobalIndexProcedure.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateGlobalIndexProcedure.java
index 8fb6fac49e..f93d19a0dc 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateGlobalIndexProcedure.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateGlobalIndexProcedure.java
@@ -37,6 +37,7 @@ import org.apache.flink.table.procedure.ProcedureContext;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.stream.Collectors;
 
@@ -114,7 +115,7 @@ public class CreateGlobalIndexProcedure extends 
ProcedureBase {
         // Parse options
         Options userOptions = createUserOptions(table, options);
 
-        indexType = indexType.toLowerCase().trim();
+        indexType = indexType.toLowerCase(Locale.ROOT).trim();
         if (indexColumns.size() > 1) {
             // Fail fast before submitting the job: index types that do not 
support multi-column
             // throw from GlobalIndexerFactory#create, which happens before 
any indexer side effect.
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/DropGlobalIndexProcedure.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/DropGlobalIndexProcedure.java
index 098c30cbe4..d74d0d2ad7 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/DropGlobalIndexProcedure.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/DropGlobalIndexProcedure.java
@@ -46,6 +46,7 @@ import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.UUID;
 import java.util.stream.Collectors;
@@ -112,7 +113,7 @@ public class DropGlobalIndexProcedure extends ProcedureBase 
{
         PartitionPredicate partitionPredicate = parsePartitionPredicate(table, 
partitions);
 
         // Normalize index type
-        final String indexTypeLower = indexType.toLowerCase().trim();
+        final String indexTypeLower = 
indexType.toLowerCase(Locale.ROOT).trim();
 
         // Get latest snapshot
         Snapshot snapshot =
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/aggregate/LocalAggregator.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/aggregate/LocalAggregator.java
index b1a6dc8cf5..009407f085 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/aggregate/LocalAggregator.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/aggregate/LocalAggregator.java
@@ -35,6 +35,7 @@ import org.apache.paimon.utils.ProjectedRow;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 /** Local aggregator based on split statistics. */
@@ -229,7 +230,7 @@ class LocalAggregator {
         }
 
         private String resultName() {
-            return kind.name().toLowerCase();
+            return kind.name().toLowerCase(Locale.ROOT);
         }
     }
 
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/MultiTablesSinkModeTest.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/MultiTablesSinkModeTest.java
new file mode 100644
index 0000000000..42e2320769
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/MultiTablesSinkModeTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.flink.action;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The mode name is case-folded before it is matched, so the conversion has to 
pin {@link
+ * Locale#ROOT} or a name containing an 'i' stops matching under a Turkish 
default.
+ */
+class MultiTablesSinkModeTest {
+
+    private Locale original;
+
+    @BeforeEach
+    void setUp() {
+        original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+    }
+
+    @AfterEach
+    void tearDown() {
+        Locale.setDefault(original);
+    }
+
+    @Test
+    void upperCaseModeNameStillParses() {
+        // DIVIDED contains an 'I', which a locale-sensitive lowercase turns 
into a dotless one
+        assertThat(MultiTablesSinkMode.fromString("DIVIDED"))
+                .isEqualTo(MultiTablesSinkMode.DIVIDED);
+        assertThat(MultiTablesSinkMode.fromString("divided"))
+                .isEqualTo(MultiTablesSinkMode.DIVIDED);
+    }
+
+    @Test
+    void configStringRoundTrips() {
+        for (MultiTablesSinkMode mode : MultiTablesSinkMode.values()) {
+            
assertThat(MultiTablesSinkMode.fromString(mode.configString())).isEqualTo(mode);
+        }
+    }
+}
diff --git a/paimon-format/src/main/java/org/apache/orc/OrcFile.java 
b/paimon-format/src/main/java/org/apache/orc/OrcFile.java
index f482174edc..06e59cd1c9 100644
--- a/paimon-format/src/main/java/org/apache/orc/OrcFile.java
+++ b/paimon-format/src/main/java/org/apache/orc/OrcFile.java
@@ -39,6 +39,7 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 
@@ -513,7 +514,9 @@ public class OrcFile {
             blockPaddingValue = 
OrcConf.BLOCK_PADDING.getBoolean(tableProperties, conf);
             compressValue =
                     CompressionKind.valueOf(
-                            OrcConf.COMPRESS.getString(tableProperties, 
conf).toUpperCase());
+                            OrcConf.COMPRESS
+                                    .getString(tableProperties, conf)
+                                    .toUpperCase(Locale.ROOT));
             enforceBufferSize =
                     
OrcConf.ENFORCE_COMPRESSION_BUFFER_SIZE.getBoolean(tableProperties, conf);
             String versionName = 
OrcConf.WRITE_FORMAT.getString(tableProperties, conf);
diff --git 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
index b3ab44f64e..8420010267 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
@@ -94,6 +94,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -1170,8 +1171,8 @@ public class HiveCatalog extends AbstractCatalog {
 
         String externalPropValue =
                 tableOptions.getOrDefault(
-                        HIVE_EXTERNAL_TABLE_PROP.toLowerCase(),
-                        
tableOptions.get(HIVE_EXTERNAL_TABLE_PROP.toUpperCase()));
+                        HIVE_EXTERNAL_TABLE_PROP.toLowerCase(Locale.ROOT),
+                        
tableOptions.get(HIVE_EXTERNAL_TABLE_PROP.toUpperCase(Locale.ROOT)));
         return CatalogTableType.EXTERNAL.equals(tableType)
                 || "TRUE".equalsIgnoreCase(externalPropValue);
     }
@@ -1705,7 +1706,7 @@ public class HiveCatalog extends AbstractCatalog {
         } else {
             // format table
             table.getParameters().put(TABLE_TYPE_PROP, provider.name());
-            table.getParameters().put(FILE_FORMAT.key(), 
provider.name().toLowerCase());
+            table.getParameters().put(FILE_FORMAT.key(), 
provider.name().toLowerCase(Locale.ROOT));
             table.getParameters().put(TYPE.key(), FORMAT_TABLE.toString());
         }
 
diff --git 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveTableUtils.java
 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveTableUtils.java
index 56ac5b82f4..3a8e8cc8b6 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveTableUtils.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveTableUtils.java
@@ -32,6 +32,7 @@ import javax.annotation.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import static org.apache.hadoop.hive.serde.serdeConstants.FIELD_DELIM;
 import static org.apache.paimon.CoreOptions.FILE_FORMAT;
@@ -103,7 +104,7 @@ public class HiveTableUtils {
         String serLib =
                 serdeInfo.getSerializationLib() == null
                         ? ""
-                        : serdeInfo.getSerializationLib().toLowerCase();
+                        : 
serdeInfo.getSerializationLib().toLowerCase(Locale.ROOT);
         String inputFormat = sd.getInputFormat() == null ? "" : 
sd.getInputFormat();
         if (serLib.contains("parquet")) {
             format = Format.PARQUET;
@@ -132,7 +133,7 @@ public class HiveTableUtils {
         rowType.getFields().forEach(f -> builder.column(f.name(), f.type(), 
f.description()));
         options.set(PATH, location);
         options.set(TYPE, FORMAT_TABLE);
-        options.set(FILE_FORMAT, format.name().toLowerCase());
+        options.set(FILE_FORMAT, format.name().toLowerCase(Locale.ROOT));
         return builder.partitionKeys(partitionKeys)
                 .options(options.toMap())
                 .comment(comment)
diff --git 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveCloneUtils.java
 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveCloneUtils.java
index f1d412ace1..1c6bb5a349 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveCloneUtils.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveCloneUtils.java
@@ -43,6 +43,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Predicate;
@@ -205,7 +206,7 @@ public class HiveCloneUtils {
         String serLib =
                 serdeInfo.getSerializationLib() == null
                         ? ""
-                        : serdeInfo.getSerializationLib().toLowerCase();
+                        : 
serdeInfo.getSerializationLib().toLowerCase(Locale.ROOT);
         String inputFormat = sd.getInputFormat() == null ? "" : 
sd.getInputFormat();
         if (serLib.contains("avro")) {
             return "avro";
diff --git 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveTableCloneExtractor.java
 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveTableCloneExtractor.java
index 0d3baf2942..61ddb4096c 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveTableCloneExtractor.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/clone/HiveTableCloneExtractor.java
@@ -45,6 +45,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
@@ -226,10 +227,13 @@ public class HiveTableCloneExtractor implements 
HiveCloneExtractor {
     public static Map<String, String> getIdentifierPrefixOptions(
             String formatIdentifier, Map<String, String> options) {
         Map<String, String> result = new HashMap<>();
-        String prefix = formatIdentifier.toLowerCase() + ".";
+        // match against the identifier as written so the suffix is sliced at 
an offset the key
+        // actually has: lower-casing can lengthen a string, and U+0130 
lower-cases to two chars
+        String prefix = formatIdentifier + ".";
+        String lowerCasePrefix = formatIdentifier.toLowerCase(Locale.ROOT) + 
".";
         for (String key : options.keySet()) {
-            if (key.toLowerCase().startsWith(prefix)) {
-                result.put(prefix + key.substring(prefix.length()), 
options.get(key));
+            if (key.regionMatches(true, 0, prefix, 0, prefix.length())) {
+                result.put(lowerCasePrefix + key.substring(prefix.length()), 
options.get(key));
             }
         }
         return result;
@@ -238,9 +242,11 @@ public class HiveTableCloneExtractor implements 
HiveCloneExtractor {
     public static Map<String, String> getOptionsWhenCloneSplits(Table table, 
String format) {
         Map<String, String> result = new HashMap<>();
         if (FormatTable.Format.JSON.name().equalsIgnoreCase(format)) {
-            result.put(FILE_FORMAT.key(), 
FormatTable.Format.PARQUET.name().toLowerCase());
+            result.put(
+                    FILE_FORMAT.key(), 
FormatTable.Format.PARQUET.name().toLowerCase(Locale.ROOT));
         } else if (FormatTable.Format.CSV.name().equalsIgnoreCase(format)) {
-            result.put(FILE_FORMAT.key(), 
FormatTable.Format.PARQUET.name().toLowerCase());
+            result.put(
+                    FILE_FORMAT.key(), 
FormatTable.Format.PARQUET.name().toLowerCase(Locale.ROOT));
         } else {
             result.put(FILE_FORMAT.key(), format);
         }
diff --git 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/pool/CachedClientPool.java
 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/pool/CachedClientPool.java
index 483b21106b..3da673dd25 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/pool/CachedClientPool.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/pool/CachedClientPool.java
@@ -164,7 +164,7 @@ public class CachedClientPool implements 
ClientPool<IMetaStoreClient, TException
                         key);
                 confElements.put(key, conf.get(key));
             } else {
-                KeyElementType type = 
KeyElementType.valueOf(trimmed.toUpperCase());
+                KeyElementType type = 
KeyElementType.valueOf(trimmed.toUpperCase(Locale.ROOT));
                 switch (type) {
                     case UGI:
                     case USER_NAME:
diff --git 
a/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/clone/HiveTableCloneExtractorTest.java
 
b/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/clone/HiveTableCloneExtractorTest.java
new file mode 100644
index 0000000000..dcceed0a15
--- /dev/null
+++ 
b/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/clone/HiveTableCloneExtractorTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.hive.clone;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+/** Tests for the format-prefixed option filtering in {@link 
HiveTableCloneExtractor}. */
+class HiveTableCloneExtractorTest {
+
+    /** U+0130, whose lower case under {@link Locale#ROOT} is the two 
characters below. */
+    private static final String DOTTED_CAPITAL_I = "İ";
+
+    private static final String LOWER_CASE_DOTTED_I = "i̇";
+
+    @Test
+    void prefixIsMatchedCaseInsensitively() {
+        Map<String, String> options = new HashMap<>();
+        options.put("ORC.compression", "zstd");
+        options.put("avro.codec", "snappy");
+
+        assertThat(HiveTableCloneExtractor.getIdentifierPrefixOptions("orc", 
options))
+                .containsExactly(entry("orc.compression", "zstd"));
+    }
+
+    @Test
+    void anIdentifierThatLowerCasesLongerKeepsItsOptions() {
+        
assertThat(DOTTED_CAPITAL_I.toLowerCase(Locale.ROOT)).isEqualTo(LOWER_CASE_DOTTED_I);
+
+        Map<String, String> options = new HashMap<>();
+        options.put(DOTTED_CAPITAL_I + ".compression", "zstd");
+
+        // slicing the key at the length of the lower-cased prefix would drop 
the "c"
+        
assertThat(HiveTableCloneExtractor.getIdentifierPrefixOptions(DOTTED_CAPITAL_I, 
options))
+                .containsExactly(entry(LOWER_CASE_DOTTED_I + ".compression", 
"zstd"));
+    }
+
+    @Test
+    void aKeyThatIsOnlyThePrefixYieldsAnEmptySuffix() {
+        Map<String, String> options = new HashMap<>();
+        options.put(DOTTED_CAPITAL_I + ".", "zstd");
+
+        // this key is shorter than the lower-cased prefix, so slicing at its 
length overruns it
+        
assertThat(HiveTableCloneExtractor.getIdentifierPrefixOptions(DOTTED_CAPITAL_I, 
options))
+                .containsExactly(entry(LOWER_CASE_DOTTED_I + ".", "zstd"));
+    }
+}
diff --git 
a/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/pool/TestCachedClientPool.java
 
b/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/pool/TestCachedClientPool.java
index 0b14565382..ea551e6e44 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/pool/TestCachedClientPool.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/pool/TestCachedClientPool.java
@@ -38,6 +38,7 @@ import java.io.File;
 import java.io.IOException;
 import java.security.PrivilegedAction;
 import java.util.List;
+import java.util.Locale;
 import java.util.UUID;
 
 import static 
org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTORECONNECTURLKEY;
@@ -59,6 +60,23 @@ public class TestCachedClientPool {
                 .hasMessage("Unknown key element conf");
     }
 
+    @Test
+    public void testExtractKeyUnderATurkishDefaultLocale() {
+        // UGI contains an 'I', so a locale-sensitive uppercase asks the enum 
for UGİ
+        Locale original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+        try {
+            assertThat(
+                            CachedClientPool.extractKey(
+                                    HiveMetaStoreClient.class.getName(),
+                                    "ugi",
+                                    new Configuration()))
+                    .isNotNull();
+        } finally {
+            Locale.setDefault(original);
+        }
+    }
+
     @Test
     public void testCacheKeyNotSame() {
         // client1 use cache key type:paimon
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/HiveSchema.java
 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/HiveSchema.java
index aac33db870..7321a58aa3 100644
--- 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/HiveSchema.java
+++ 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/HiveSchema.java
@@ -50,6 +50,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -172,10 +173,10 @@ public class HiveSchema {
                     paimonSchema.fields().stream()
                             .collect(
                                     Collectors.toMap(
-                                            dataField -> 
dataField.name().toLowerCase(),
+                                            dataField -> 
dataField.name().toLowerCase(Locale.ROOT),
                                             Function.identity()));
             for (int i = 0; i < columnNames.size(); i++) {
-                String columnName = columnNames.get(i).toLowerCase();
+                String columnName = 
columnNames.get(i).toLowerCase(Locale.ROOT);
                 if (Objects.equals(columnName, tagToPartField)) {
                     // ignore tagToPartField, it should just be a string type
                     continue;
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/PaimonMetaHook.java
 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/PaimonMetaHook.java
index c032c2ff43..5c96a5e808 100644
--- 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/PaimonMetaHook.java
+++ 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/PaimonMetaHook.java
@@ -44,6 +44,7 @@ import org.slf4j.LoggerFactory;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -78,8 +79,8 @@ public class PaimonMetaHook implements HiveMetaHook {
 
         
table.getSd().setInputFormat(PaimonInputFormat.class.getCanonicalName());
         
table.getSd().setOutputFormat(PaimonOutputFormat.class.getCanonicalName());
-        table.setDbName(table.getDbName().toLowerCase());
-        table.setTableName(table.getTableName().toLowerCase());
+        table.setDbName(table.getDbName().toLowerCase(Locale.ROOT));
+        table.setTableName(table.getTableName().toLowerCase(Locale.ROOT));
         String location = LocationKeyExtractor.getPaimonLocation(conf, table);
         Identifier identifier = Identifier.create(table.getDbName(), 
table.getTableName());
         if (location == null) {
@@ -115,7 +116,7 @@ public class PaimonMetaHook implements HiveMetaHook {
                 .forEachRemaining(
                         fieldSchema ->
                                 schemaBuilder.column(
-                                        fieldSchema.getName().toLowerCase(),
+                                        
fieldSchema.getName().toLowerCase(Locale.ROOT),
                                         toPaimonType(fieldSchema.getType()),
                                         fieldSchema.getComment()));
         // partition columns
@@ -128,14 +129,14 @@ public class PaimonMetaHook implements HiveMetaHook {
                     .forEachRemaining(
                             fieldSchema ->
                                     schemaBuilder.column(
-                                            
fieldSchema.getName().toLowerCase(),
+                                            
fieldSchema.getName().toLowerCase(Locale.ROOT),
                                             
toPaimonType(fieldSchema.getType()),
                                             fieldSchema.getComment()));
 
             List<String> partitionKeys =
                     table.getPartitionKeys().stream()
                             .map(FieldSchema::getName)
-                            .map(String::toLowerCase)
+                            .map(s -> s.toLowerCase(Locale.ROOT))
                             .collect(Collectors.toList());
             schemaBuilder.partitionKeys(partitionKeys);
         }
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/SearchArgumentToPredicateConverter.java
 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/SearchArgumentToPredicateConverter.java
index 38830af66a..202cceae29 100644
--- 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/SearchArgumentToPredicateConverter.java
+++ 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/SearchArgumentToPredicateConverter.java
@@ -35,6 +35,7 @@ import javax.annotation.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -62,11 +63,15 @@ public class SearchArgumentToPredicateConverter {
         this.root = searchArgument.getExpression();
         this.leaves = searchArgument.getLeaves();
         this.hiveColumnNames =
-                
columnNames.stream().map(String::toLowerCase).collect(Collectors.toList());
+                columnNames.stream()
+                        .map(s -> s.toLowerCase(Locale.ROOT))
+                        .collect(Collectors.toList());
         this.columnTypes = columnTypes;
         if (readColumnNames != null) {
             readColumnNames =
-                    
readColumnNames.stream().map(String::toLowerCase).collect(Collectors.toSet());
+                    readColumnNames.stream()
+                            .map(s -> s.toLowerCase(Locale.ROOT))
+                            .collect(Collectors.toSet());
         }
         this.readColumnNames = readColumnNames;
 
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/mapred/PaimonRecordReader.java
 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/mapred/PaimonRecordReader.java
index 3232868b53..1cd93a9f24 100644
--- 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/mapred/PaimonRecordReader.java
+++ 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/mapred/PaimonRecordReader.java
@@ -43,6 +43,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -88,7 +89,7 @@ public class PaimonRecordReader implements RecordReader<Void, 
RowDataContainer>
                         .boxed()
                         .collect(
                                 Collectors.toMap(
-                                        index -> 
paimonColumns.get(index).toLowerCase(),
+                                        index -> 
paimonColumns.get(index).toLowerCase(Locale.ROOT),
                                         index -> index,
                                         (existing, replacement) -> existing,
                                         LinkedHashMap::new));
diff --git 
a/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorMetric.java
 
b/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorMetric.java
index f4240d7013..212d8a890b 100644
--- 
a/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorMetric.java
+++ 
b/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorMetric.java
@@ -18,6 +18,8 @@
 
 package org.apache.paimon.lumina.index;
 
+import java.util.Locale;
+
 /** Enumeration of supported Lumina vector similarity metrics. */
 public enum LuminaVectorMetric {
 
@@ -45,7 +47,7 @@ public enum LuminaVectorMetric {
     }
 
     public static LuminaVectorMetric fromString(String name) {
-        return valueOf(name.toUpperCase());
+        return valueOf(name.toUpperCase(Locale.ROOT));
     }
 
     /** Resolves a Lumina native metric name (e.g. "l2") to the corresponding 
enum constant. */
diff --git 
a/paimon-lumina/src/test/java/org/apache/paimon/lumina/index/LuminaVectorMetricTest.java
 
b/paimon-lumina/src/test/java/org/apache/paimon/lumina/index/LuminaVectorMetricTest.java
new file mode 100644
index 0000000000..9b46ea0ebe
--- /dev/null
+++ 
b/paimon-lumina/src/test/java/org/apache/paimon/lumina/index/LuminaVectorMetricTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.lumina.index;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * A metric name is upper-cased before {@code valueOf}, so the conversion has 
to pin {@link
+ * Locale#ROOT} or a name containing an 'i' names no enum constant under a 
Turkish default.
+ */
+class LuminaVectorMetricTest {
+
+    private Locale original;
+
+    @BeforeEach
+    void setUp() {
+        original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+    }
+
+    @AfterEach
+    void tearDown() {
+        Locale.setDefault(original);
+    }
+
+    @Test
+    void everyMetricNameParsesFromItsLowerCaseForm() {
+        // COSINE contains an 'I': a locale-sensitive uppercase asks for COSİNE
+        for (LuminaVectorMetric metric : LuminaVectorMetric.values()) {
+            
assertThat(LuminaVectorMetric.fromString(metric.name().toLowerCase(Locale.ROOT)))
+                    .isEqualTo(metric);
+        }
+    }
+}
diff --git 
a/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/SparkCatalog.java
 
b/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/SparkCatalog.java
index ab94e9987a..03f0a5e8cd 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/SparkCatalog.java
+++ 
b/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/SparkCatalog.java
@@ -614,7 +614,7 @@ public class SparkCatalog extends SparkBaseCatalog
         if (!usePaimon(provider)) {
             if (isFormatTable(provider)) {
                 normalizedProperties.put(TYPE.key(), FORMAT_TABLE.toString());
-                normalizedProperties.put(FILE_FORMAT.key(), 
provider.toLowerCase());
+                normalizedProperties.put(FILE_FORMAT.key(), 
provider.toLowerCase(Locale.ROOT));
             } else {
                 throw new UnsupportedOperationException(
                         String.format(
diff --git 
a/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/catalog/FormatTableCatalog.java
 
b/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/catalog/FormatTableCatalog.java
index 3893e67068..096216a31e 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/catalog/FormatTableCatalog.java
+++ 
b/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/catalog/FormatTableCatalog.java
@@ -22,7 +22,6 @@ import org.apache.paimon.CoreOptions;
 import org.apache.paimon.format.csv.CsvOptions;
 import org.apache.paimon.format.text.TextOptions;
 import org.apache.paimon.options.Options;
-import org.apache.paimon.spark.SparkSource;
 import org.apache.paimon.spark.SparkTypeUtils;
 import org.apache.paimon.spark.format.PaimonFormatTable;
 import org.apache.paimon.table.FormatTable;
@@ -56,7 +55,17 @@ import java.util.Map;
 public interface FormatTableCatalog {
 
     default boolean isFormatTable(@Nullable String provide) {
-        return provide != null && 
SparkSource.FORMAT_NAMES().contains(provide.toLowerCase());
+        if (provide == null) {
+            return false;
+        }
+        // compare against the enum names rather than a pre-lowered list, so 
the answer does not
+        // depend on the locale that was in effect when that list was built
+        for (FormatTable.Format format : FormatTable.Format.values()) {
+            if (format.name().equalsIgnoreCase(provide)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     default Table toSparkFormatTable(Identifier ident, FormatTable 
formatTable) {
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/SparkSource.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/SparkSource.scala
index 0e7c1b8b60..9767f4a57e 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/SparkSource.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/SparkSource.scala
@@ -39,6 +39,7 @@ import org.apache.spark.sql.types.StructType
 import org.apache.spark.sql.util.CaseInsensitiveStringMap
 
 import java.util.{Map => JMap}
+import java.util.Locale
 
 import scala.collection.JavaConverters._
 
@@ -130,7 +131,7 @@ object SparkSource {
 
   val NAME = "paimon"
 
-  val FORMAT_NAMES: Seq[String] = 
Format.values.map(_.toString.toLowerCase).toSeq
+  val FORMAT_NAMES: Seq[String] = 
Format.values.map(_.toString.toLowerCase(Locale.ROOT)).toSeq
 
   // Spark dataframe read options
   private val CATALOG = "catalog"
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonFunctionResolver.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonFunctionResolver.scala
index 61426a52ec..3d4ee94876 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonFunctionResolver.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonFunctionResolver.scala
@@ -33,6 +33,8 @@ import org.apache.spark.sql.connector.catalog.CatalogPlugin
 import org.apache.spark.sql.types.{BinaryType, DataType, DayTimeIntervalType, 
LongType, NullType, StringType}
 import org.apache.spark.unsafe.types.UTF8String
 
+import java.util.Locale
+
 case class PaimonFunctionResolver(spark: SparkSession) extends 
Rule[LogicalPlan] {
 
   protected lazy val catalogManager = spark.sessionState.catalogManager
@@ -122,7 +124,7 @@ case class PaimonFunctionResolver(spark: SparkSession) 
extends Rule[LogicalPlan]
       case actual if actual == expectedType => expression
       case actual =>
         throw new UnsupportedOperationException(
-          s"$argumentName must be ${expectedType.simpleString.toUpperCase} 
type, " +
+          s"$argumentName must be 
${expectedType.simpleString.toUpperCase(Locale.ROOT)} type, " +
             s"but found ${actual.simpleString}")
     }
   }
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/ReplacePaimonFunctions.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/ReplacePaimonFunctions.scala
index 2c981b23a5..3abe903768 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/ReplacePaimonFunctions.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/ReplacePaimonFunctions.scala
@@ -37,6 +37,8 @@ import 
org.apache.spark.sql.connector.catalog.PaimonCatalogImplicits._
 import org.apache.spark.sql.types.{BinaryType, DataType, DayTimeIntervalType, 
NullType, StringType}
 import org.apache.spark.unsafe.types.UTF8String
 
+import java.util.Locale
+
 object ReplacePaimonFunctions {
 
   def resolveDescriptorToPresignedUrl(
@@ -226,7 +228,7 @@ case class ReplacePaimonFunctions(spark: SparkSession) 
extends Rule[LogicalPlan]
       case actual if actual == expectedType => expression
       case actual =>
         throw new UnsupportedOperationException(
-          s"$argumentName must be ${expectedType.simpleString.toUpperCase} 
type, " +
+          s"$argumentName must be 
${expectedType.simpleString.toUpperCase(Locale.ROOT)} type, " +
             s"but found ${actual.simpleString}")
     }
   }
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/CopyOptions.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/CopyOptions.scala
index 3e5e35b2b7..71a988d61f 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/CopyOptions.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/CopyOptions.scala
@@ -18,6 +18,8 @@
 
 package org.apache.paimon.spark.catalyst.plans.logical
 
+import java.util.Locale
+
 sealed trait OnErrorMode
 
 object OnErrorMode {
@@ -57,7 +59,7 @@ case class CopyFileFormat(formatType: FileFormatType, 
options: Map[String, Strin
         options.foreach {
           case (k, v) =>
             k match {
-              case "MULTI_LINE" => mapped("multiLine") = v.toLowerCase
+              case "MULTI_LINE" => mapped("multiLine") = 
v.toLowerCase(Locale.ROOT)
               case "COMPRESSION" => mapped("compression") = v
               case _ =>
             }
@@ -84,7 +86,7 @@ case class CopyFileFormat(formatType: FileFormatType, 
options: Map[String, Strin
           case (k, v) =>
             k match {
               case "FIELD_DELIMITER" => mapped("sep") = v
-              case "HEADER" => mapped("header") = v.toLowerCase
+              case "HEADER" => mapped("header") = v.toLowerCase(Locale.ROOT)
               case "QUOTE" => mapped("quote") = v
               case "ESCAPE" => mapped("escape") = v
               case "COMPRESSION" => mapped("compression") = v
@@ -226,7 +228,7 @@ object CopyFileFormat {
   val LIST_SEPARATOR: String = "\u001f"
 
   def parseFormatType(typeStr: String): FileFormatType = {
-    typeStr.toUpperCase match {
+    typeStr.toUpperCase(Locale.ROOT) match {
       case "CSV" => FileFormatType.CSV
       case "JSON" => FileFormatType.JSON
       case "PARQUET" => FileFormatType.PARQUET
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/write/WriteHelper.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/write/WriteHelper.scala
index 9de665c12b..5393697a50 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/write/WriteHelper.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/write/WriteHelper.scala
@@ -33,6 +33,8 @@ import org.apache.spark.sql.connector.metric.CustomTaskMetric
 import org.apache.spark.sql.execution.SQLExecution
 import org.apache.spark.sql.execution.metric.SQLMetrics
 
+import java.util.Locale
+
 import scala.collection.JavaConverters._
 
 trait WriteHelper extends Logging {
@@ -52,7 +54,9 @@ trait WriteHelper extends Logging {
     val executionMetrics = Compatibility.getExecutionMetrics(spark, 
executionId.toLong).distinct
     val metricUpdates = executionMetrics.flatMap {
       m =>
-        commitMetrics.find(x => 
m.metricType.toLowerCase.contains(x.name.toLowerCase)) match {
+        commitMetrics.find(
+          x =>
+            
m.metricType.toLowerCase(Locale.ROOT).contains(x.name.toLowerCase(Locale.ROOT)))
 match {
           case Some(customTaskMetric) => Some((m.accumulatorId, 
customTaskMetric.value()))
           case None => None
         }
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
index f5986492b6..a4aaf3ab69 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
@@ -34,6 +34,8 @@ import 
org.apache.spark.sql.catalyst.parser.extensions.PaimonSqlExtensionsParser
 import org.apache.spark.sql.catalyst.plans.logical._
 import org.apache.spark.sql.execution.command.{CreateTableLikeCommand => 
SparkCreateTableLikeCommand}
 
+import java.util.Locale
+
 import scala.collection.JavaConverters._
 import scala.collection.mutable
 
@@ -239,7 +241,7 @@ class PaimonSqlExtensionsAstBuilder(delegate: 
ParserInterface)
 
     opts.foreach {
       opt =>
-        val key = opt.key.getText.toUpperCase
+        val key = opt.key.getText.toUpperCase(Locale.ROOT)
         if (!seen.add(key)) {
           throw new IllegalArgumentException(s"Duplicate FILE_FORMAT option: 
$key")
         }
diff --git 
a/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/catalog/FormatTableCatalogTest.java
 
b/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/catalog/FormatTableCatalogTest.java
new file mode 100644
index 0000000000..5743389898
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/catalog/FormatTableCatalogTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.spark.catalog;
+
+import org.apache.paimon.table.FormatTable;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * {@code MOSAIC} contains an 'I', so a provider name folded under a Turkish 
default locale no
+ * longer matches the enum constant it names.
+ */
+class FormatTableCatalogTest {
+
+    private final FormatTableCatalog catalog = new FormatTableCatalog() {};
+
+    private Locale original;
+
+    @BeforeEach
+    void setUp() {
+        original = Locale.getDefault();
+        Locale.setDefault(new Locale("tr", "TR"));
+    }
+
+    @AfterEach
+    void tearDown() {
+        Locale.setDefault(original);
+    }
+
+    @Test
+    void everyFormatIsRecognizedInEitherCase() {
+        for (FormatTable.Format format : FormatTable.Format.values()) {
+            assertThat(catalog.isFormatTable(format.name())).as("%s", 
format).isTrue();
+            
assertThat(catalog.isFormatTable(format.name().toLowerCase(Locale.ROOT)))
+                    .as("%s lower case", format)
+                    .isTrue();
+        }
+    }
+
+    @Test
+    void aNameThatIsNotAFormatIsRejected() {
+        assertThat(catalog.isFormatTable(null)).isFalse();
+        assertThat(catalog.isFormatTable("")).isFalse();
+        assertThat(catalog.isFormatTable("paimon")).isFalse();
+        assertThat(catalog.isFormatTable("orcish")).isFalse();
+    }
+}
diff --git 
a/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java
 
b/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java
index 06f33273e2..5a4be336f5 100644
--- 
a/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java
+++ 
b/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java
@@ -329,7 +329,7 @@ public class JarFileChecker {
     }
 
     private static String getFileName(Path path) {
-        return path.getFileName().toString().toLowerCase();
+        return path.getFileName().toString().toLowerCase(Locale.ROOT);
     }
 
     private static boolean pathStartsWith(Path file, String path) {

Reply via email to