github-actions[bot] commented on code in PR #69526:
URL: https://github.com/apache/doris/pull/69526#discussion_r4366625863


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertIntoTVFCommand.java:
##########
@@ -185,6 +188,10 @@ private void deleteExistingFilesInFE(String tvfName, 
Map<String, String> props)
         fsCopyProps.remove("compress_type");
 
         StorageAdapter storageAdapter = StorageAdapter.of(fsCopyProps);
+        if (storageAdapter.getType() == StorageTypeId.HDFS) {

Review Comment:
   [P1] Gate the LOCAL adapter selected for FE cleanup
   
   With `enable_local_tvf=false`, a global LOAD user can execute `INSERT INTO 
s3('file_path'='/tmp/local_gate_dir/prefix_', 'format'='csv', 
'fs.local.support'='true', 'delete_existing_files'='true') SELECT 1`. The 
explicit support flag makes `StorageAdapter.of` select the LOCAL provider 
during both sink binding and cleanup. This HDFS-only condition then skips 
admission, and `FileSystemFactory.getFileSystem(storageAdapter)` preserves that 
LOCAL binding: `LocalFileSystem.delete(..., true)` recursively deletes 
`/tmp/local_gate_dir/` on the FE before coordinator creation or BE writer 
setup. A subsequent S3 failure cannot prevent or undo the deletion. Despite its 
test-only comment, the local plugin is included in normal `build.sh` packaging. 
Gate `StorageTypeId.LOCAL` before filesystem creation and cover this 
effective-adapter case with a no-filesystem-interaction test. This is a 
separate FE cleanup path from the fixed nominal-LOCAL and JNI writer findings.



##########
fe/fe-core/src/main/java/org/apache/doris/tablefunction/LocalTableValuedFunction.java:
##########
@@ -137,6 +140,129 @@ private void getFileListFromBackend() throws 
AnalysisException {
         }
     }
 
+    /** Apply LOCAL admission to the effective sink before planning or 
filesystem side effects. */
+    public static void checkSinkEnabled(String tvfName, Map<String, String> 
properties) {
+        if ("local".equalsIgnoreCase(tvfName) || 
isLocalWriter(properties.getOrDefault("writer_class", ""))) {
+            checkEnabled();
+        }
+        if ("hdfs".equalsIgnoreCase(tvfName)) {
+            if (!properties.containsKey("writer_class")) {
+                checkHdfsSinkEnabled(properties);
+            }
+            if 
(Boolean.parseBoolean(properties.getOrDefault("delete_existing_files", 
"false"))) {
+                
checkHadoopFileSystemEnabled(properties.getOrDefault("file_path", ""), 
properties);
+            }
+        }
+    }
+
+    private static boolean isLocalWriter(String writer) {
+        // BE splits the complete identifier first, then passes each half 
through JNI C strings.
+        int separator = writer.indexOf(':');
+        return separator > 0 && 
"java-writer".equals(nativeStringPrefix(writer.substring(0, separator)))
+                && 
"local-file".equals(nativeStringPrefix(writer.substring(separator + 1)));
+    }
+
+    /** Check the NameNode and provider used by the native FILE_HDFS writer. */
+    public static void checkHdfsSinkEnabled(Map<String, String> properties) {
+        String nameNode = 
nativeStringPrefix(properties.getOrDefault("fs.defaultFS", "")).trim();
+        if ("default".equals(nameNode)) {
+            // libhdfs delegates this selector to the BE's defaults, which may 
select local storage.
+            checkEnabled();
+        }
+        // libhdfs prefixes bare NameNodes with hdfs:// rather than using the 
output path's scheme.
+        checkHadoopSchemeEnabled(nameNode.contains("://") ? 
uriScheme(nameNode) : "hdfs", properties);
+    }
+
+    /** Check Hadoop's path/default-filesystem selection before FE-side 
cleanup. */
+    public static void checkHadoopFileSystemEnabled(String path, Map<String, 
String> properties) {
+        String scheme = uriScheme(path);
+        if (!scheme.isEmpty()) {
+            checkHadoopSchemeEnabled(scheme, properties);
+            return;
+        }
+        String defaultFs = hadoopSelectorProperty("fs.defaultFS", properties);
+        String legacyDefaultFs = hadoopSelectorProperty("fs.default.name", 
properties);
+        // Configuration.set synchronizes aliases; either value can win when 
the map is applied.
+        // Do not assume that the canonical key overrides a local legacy 
selector.
+        if (defaultFs != null) {
+            checkHadoopDefaultEnabled(defaultFs, properties);
+        }
+        if (legacyDefaultFs != null) {
+            checkHadoopDefaultEnabled(legacyDefaultFs, properties);
+        }
+        if (defaultFs == null && legacyDefaultFs == null) {
+            checkHadoopSchemeEnabled("file", properties);
+        }
+    }
+
+    private static void checkHadoopDefaultEnabled(String value, Map<String, 
String> properties) {
+        value = hadoopSelectorValue(value).trim();
+        // Hadoop retains the old "local" default-FS spelling.
+        String scheme = "local".equals(value) ? "file" : uriScheme(value);
+        checkHadoopSchemeEnabled(scheme.isEmpty() ? "hdfs" : scheme, 
properties);
+    }
+
+    private static void checkHadoopSchemeEnabled(String scheme, Map<String, 
String> properties) {
+        if ("file".equalsIgnoreCase(scheme)) {
+            checkEnabled();
+        }
+        String implementationKey = "fs." + scheme + ".impl";

Review Comment:
   [P1] Check delegated ViewFS targets before admitting Hadoop sinks
   
   With `enable_local_tvf=false`, `INSERT INTO 
hdfs('file_path'='/data/local_gate_', 'format'='csv', 
'fs.defaultFS'='viewfs://local/', 
'fs.viewfs.mounttable.local.link./data'='file:///tmp') SELECT 1` passes both 
the raw and normalized admission checks: the scheme is `viewfs` and no direct 
local implementation override is needed. `HdfsProperties` preserves the mount 
configuration, so `FileFactory` opens the native FILE_HDFS writer through 
libhdfs and Hadoop's built-in ViewFileSystem. Its [create 
implementation](https://github.com/apache/hadoop/blob/rel/release-3.4.2/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java#L445-L456)
 resolves `/data` to the local mount and delegates creation, producing 
`/tmp/local_gate_<query>_0.csv` on the BE with only global LOAD privilege. 
Checking the top-level scheme/direct class therefore does not enforce the new 
local-storage policy. Validate delegated targets, including 
normalized/resource-derived ViewFS
  mounts, or require opt-in when their effective storage cannot be established; 
add off/on INSERT/EXPLAIN and direct-binding coverage.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to