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

hello-stephen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new c9f2dd64508 [fix](load) Avoid global BE auth precheck for stream load 
(#66629)
c9f2dd64508 is described below

commit c9f2dd6450891c304fb5bede898a3a245c808d42
Author: Gavin Chou <[email protected]>
AuthorDate: Wed Aug 12 15:13:49 2026 +0800

    [fix](load) Avoid global BE auth precheck for stream load (#66629)
    
    ## Summary
    - Remove the generic BE HTTP auth precheck from Stream Load, Stream Load
    2PC, and HTTP Stream.
    - Keep the existing load-specific path: BE parses Basic auth and FE load
    RPCs check LOAD against the actual db/table/txn.
    - Add docker regression coverage for table-level and database-level LOAD
    users with BE enable_all_http_auth both off and on.
    
    ## Testing
    - sh format_code.sh on changed BE files
    - git diff --check
    - ninja -C be/ut_build_ASAN stream_load.cpp.o stream_load_2pc.cpp.o
    http_stream.cpp.o
    - run-regression-test selected both new docker suites; local regression
    config skips docker execution, but framework compilation and suite
    discovery passed
    
    Co-authored-by: gavinchou <[email protected]>
---
 be/src/service/http/action/http_stream.cpp         |  14 +-
 be/src/service/http/action/http_stream.h           |   6 +-
 be/src/service/http/action/stream_load.cpp         |  15 +-
 be/src/service/http/action/stream_load.h           |   6 +-
 be/src/service/http/action/stream_load_2pc.cpp     |   8 +-
 be/src/service/http/action/stream_load_2pc.h       |   5 +-
 .../test_dml_stream_load_be_auth_docker.groovy     | 321 +++++++++++++++++++++
 7 files changed, 345 insertions(+), 30 deletions(-)

diff --git a/be/src/service/http/action/http_stream.cpp 
b/be/src/service/http/action/http_stream.cpp
index cd80517942e..ce33b3d8ef6 100644
--- a/be/src/service/http/action/http_stream.cpp
+++ b/be/src/service/http/action/http_stream.cpp
@@ -92,10 +92,10 @@ 
DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(http_stream_requests_total, MetricUnit::REQ
 DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(http_stream_duration_ms, 
MetricUnit::MILLISECONDS);
 DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(http_stream_current_processing, 
MetricUnit::REQUESTS);
 
-HttpStreamAction::HttpStreamAction(ExecEnv* exec_env)
-        : HttpHandlerWithAuth(exec_env, TPrivilegeHier::GLOBAL, 
TPrivilegeType::LOAD) {
-    // Use LOAD privilege type: requires LOAD permission
-    // Note: _exec_env is set by parent class HttpHandlerWithAuth
+HttpStreamAction::HttpStreamAction(ExecEnv* exec_env) : _exec_env(exec_env) {
+    // HTTP stream derives db/table from the SQL header and then forwards the
+    // request credentials to FE load RPCs for table-scoped LOAD checks. The 
generic
+    // BE HTTP auth hook only supports caller-provided resource metadata.
     _http_stream_entity =
             
DorisMetrics::instance()->metric_registry()->register_entity("http_stream");
     INT_COUNTER_METRIC_REGISTER(_http_stream_entity, 
http_stream_requests_total);
@@ -182,12 +182,6 @@ Status HttpStreamAction::_handle(HttpRequest* http_req, 
std::shared_ptr<StreamLo
 }
 
 int HttpStreamAction::on_header(HttpRequest* req) {
-    // Call parent's auth check first
-    int ret = HttpHandlerWithAuth::on_header(req);
-    if (ret != 0) {
-        return ret; // Auth failed, return error
-    }
-
     http_stream_current_processing->increment(1);
 
     std::shared_ptr<StreamLoadContext> ctx = 
std::make_shared<StreamLoadContext>(_exec_env);
diff --git a/be/src/service/http/action/http_stream.h 
b/be/src/service/http/action/http_stream.h
index 03b6a7539a2..5ecb19740fb 100644
--- a/be/src/service/http/action/http_stream.h
+++ b/be/src/service/http/action/http_stream.h
@@ -22,7 +22,7 @@
 #include <functional>
 
 #include "load/message_body_sink.h"
-#include "service/http/http_handler_with_auth.h"
+#include "service/http/http_handler.h"
 #include "util/client_cache.h"
 
 namespace doris {
@@ -31,7 +31,7 @@ class ExecEnv;
 class Status;
 class StreamLoadContext;
 
-class HttpStreamAction : public HttpHandlerWithAuth {
+class HttpStreamAction : public HttpHandler {
 public:
     HttpStreamAction(ExecEnv* exec_env);
     ~HttpStreamAction() override;
@@ -53,6 +53,8 @@ private:
     Status _handle_group_commit(HttpRequest* http_req, 
std::shared_ptr<StreamLoadContext> ctx);
 
 private:
+    ExecEnv* _exec_env;
+
     std::shared_ptr<MetricEntity> _http_stream_entity;
     IntCounter* http_stream_requests_total;
     IntCounter* http_stream_duration_ms;
diff --git a/be/src/service/http/action/stream_load.cpp 
b/be/src/service/http/action/stream_load.cpp
index 1b67543f215..81d1fe9ccef 100644
--- a/be/src/service/http/action/stream_load.cpp
+++ b/be/src/service/http/action/stream_load.cpp
@@ -94,9 +94,11 @@ static const std::string ASYNC_MODE = "async_mode";
 TStreamLoadPutResult k_stream_load_put_result;
 #endif
 
-StreamLoadAction::StreamLoadAction(ExecEnv* exec_env)
-        : HttpHandlerWithAuth(exec_env, TPrivilegeHier::GLOBAL, 
TPrivilegeType::LOAD) {
-    // Use LOAD privilege type: requires LOAD permission
+StreamLoadAction::StreamLoadAction(ExecEnv* exec_env) : _exec_env(exec_env) {
+    // Stream load forwards the parsed HTTP credentials to FE load RPCs, where 
LOAD
+    // privilege is checked against the actual db/table/txn. A generic BE HTTP
+    // pre-check cannot model every stream-load variant and would duplicate 
that
+    // resource-scoped authorization.
     _stream_load_entity =
             
DorisMetrics::instance()->metric_registry()->register_entity("stream_load");
     INT_COUNTER_METRIC_REGISTER(_stream_load_entity, 
streaming_load_requests_total);
@@ -240,13 +242,6 @@ void 
StreamLoadAction::_send_reply(std::shared_ptr<StreamLoadContext> ctx, HttpR
 }
 
 int StreamLoadAction::on_header(HttpRequest* req) {
-    // Call parent's auth check first
-    int ret = HttpHandlerWithAuth::on_header(req);
-    if (ret != 0) {
-        return ret; // Auth failed, return error
-    }
-
-    // Continue with stream load specific header processing
     req->mark_send_reply();
 
     streaming_load_current_processing->increment(1);
diff --git a/be/src/service/http/action/stream_load.h 
b/be/src/service/http/action/stream_load.h
index 89b18f045cb..29fc92065ed 100644
--- a/be/src/service/http/action/stream_load.h
+++ b/be/src/service/http/action/stream_load.h
@@ -22,7 +22,7 @@
 #include <string>
 
 #include "common/metrics/metrics.h"
-#include "service/http/http_handler_with_auth.h"
+#include "service/http/http_handler.h"
 
 namespace doris {
 
@@ -31,7 +31,7 @@ class Status;
 class StreamLoadContext;
 class HttpRequest;
 
-class StreamLoadAction : public HttpHandlerWithAuth {
+class StreamLoadAction : public HttpHandler {
 public:
     StreamLoadAction(ExecEnv* exec_env);
     ~StreamLoadAction() override;
@@ -59,6 +59,8 @@ private:
     void _send_reply(std::shared_ptr<StreamLoadContext> ctx, HttpRequest* req);
 
 private:
+    ExecEnv* _exec_env;
+
     std::shared_ptr<MetricEntity> _stream_load_entity;
     IntCounter* streaming_load_requests_total;
     IntCounter* streaming_load_duration_ms;
diff --git a/be/src/service/http/action/stream_load_2pc.cpp 
b/be/src/service/http/action/stream_load_2pc.cpp
index 0239ed9fee6..15ca8066cf9 100644
--- a/be/src/service/http/action/stream_load_2pc.cpp
+++ b/be/src/service/http/action/stream_load_2pc.cpp
@@ -39,10 +39,10 @@
 
 namespace doris {
 
-StreamLoad2PCAction::StreamLoad2PCAction(ExecEnv* exec_env)
-        : HttpHandlerWithAuth(exec_env, TPrivilegeHier::GLOBAL, 
TPrivilegeType::LOAD) {
-    // Use LOAD privilege type: requires LOAD permission
-    // Note: _exec_env is set by parent class HttpHandlerWithAuth
+StreamLoad2PCAction::StreamLoad2PCAction(ExecEnv* exec_env) : 
_exec_env(exec_env) {
+    // 2PC commit/abort resolves the transaction's table list in FE and checks 
LOAD
+    // privilege for each table there. A BE HTTP pre-check may only have 
db/label or
+    // txn_id, so it would be less accurate and can reject valid table-scoped 
users.
 }
 
 void StreamLoad2PCAction::handle(HttpRequest* req) {
diff --git a/be/src/service/http/action/stream_load_2pc.h 
b/be/src/service/http/action/stream_load_2pc.h
index 939e9f8dbfa..3e1b3076eee 100644
--- a/be/src/service/http/action/stream_load_2pc.h
+++ b/be/src/service/http/action/stream_load_2pc.h
@@ -19,14 +19,14 @@
 
 #include <string>
 
-#include "service/http/http_handler_with_auth.h"
+#include "service/http/http_handler.h"
 
 namespace doris {
 
 class ExecEnv;
 class HttpRequest;
 
-class StreamLoad2PCAction : public HttpHandlerWithAuth {
+class StreamLoad2PCAction : public HttpHandler {
 public:
     StreamLoad2PCAction(ExecEnv* exec_env);
 
@@ -36,6 +36,7 @@ public:
     std::string get_success_info(const std::string msg, const std::string 
txn_operation);
 
 private:
+    ExecEnv* _exec_env;
 };
 
 } // namespace doris
diff --git 
a/regression-test/suites/auth_call/test_dml_stream_load_be_auth_docker.groovy 
b/regression-test/suites/auth_call/test_dml_stream_load_be_auth_docker.groovy
new file mode 100644
index 00000000000..46d06e5df81
--- /dev/null
+++ 
b/regression-test/suites/auth_call/test_dml_stream_load_be_auth_docker.groovy
@@ -0,0 +1,321 @@
+// 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.
+
+import org.apache.doris.regression.suite.ClusterOptions
+
+suite("test_dml_stream_load_be_auth_off_docker", "docker,auth_call") {
+    def options = new ClusterOptions()
+    options.cloudMode = true
+    options.feNum = 1
+    options.beNum = 1
+
+    docker(options) {
+        String suiteName = "test_dml_stream_load_be_auth_off_docker"
+        String tableUser = "${suiteName}_table_user"
+        String dbUser = "${suiteName}_db_user"
+        String pwd = "C123_567p"
+        String dbName = "${suiteName}_db"
+        String tableName = "${suiteName}_tb"
+        String otherTableName = "${suiteName}_other_tb"
+        String dataFile = 
"${context.file.parent}/../../data/auth_call/stream_load_data.csv"
+
+        def fe = cluster.getFeByIndex(1)
+        def be = cluster.getAllBackends(true).get(0)
+        String feHttpAddress = "${fe.host}:${fe.httpPort}"
+        String beHttpAddress = "${be.host}:${be.httpPort}"
+
+        def parseCurlResult = { String out, String err ->
+            def lines = out.readLines()
+            assertTrue("curl output should include http code, output=${out}, 
err=${err}", !lines.isEmpty())
+            def httpCode = lines.last() as int
+            def body = lines.size() == 1 ? "" : lines[0..-2].join("\n")
+            return [httpCode, body, err]
+        }
+
+        def streamLoad = { String authUser, String endpoint, String table, 
String label,
+                           boolean followRedirect, List extraHeaders ->
+            def command = [
+                    "curl", "--noproxy", "*", "-sS", "-w", "\n%{http_code}",
+                    "-u", "${authUser}:${pwd}",
+                    "-H", "label:${label}",
+                    "-H", "column_separator:,",
+            ]
+            if (followRedirect) {
+                command.add("--location-trusted")
+            }
+            extraHeaders.each { command.addAll(["-H", it]) }
+            command.addAll([
+                    "-T", dataFile,
+                    "http://${endpoint}/api/${dbName}/${table}/_stream_load";
+            ])
+            logger.info("stream load target: ${endpoint}, table: ${table}, 
label: ${label}, user: ${authUser}")
+            def process = command.execute()
+            process.waitForOrKill(7200000)
+            def out = process.text.trim()
+            def err = process.errorStream.text.trim()
+            logger.info("stream load out: ${out}, err: ${err}")
+            return parseCurlResult(out, err)
+        }
+
+        def streamLoad2pc = { String authUser, String table, def txnId, String 
txnOperation ->
+            def command = [
+                    "curl", "--noproxy", "*", "-sS", "-w", "\n%{http_code}",
+                    "-X", "PUT",
+                    "-u", "${authUser}:${pwd}",
+                    "-H", "txn_id:${txnId}",
+                    "-H", "txn_operation:${txnOperation}",
+                    
"http://${beHttpAddress}/api/${dbName}/${table}/_stream_load_2pc";
+            ]
+            logger.info("stream load 2pc target: ${beHttpAddress}, table: 
${table}, "
+                    + "txn operation: ${txnOperation}, user: ${authUser}")
+            def process = command.execute()
+            process.waitForOrKill(7200000)
+            def out = process.text.trim()
+            def err = process.errorStream.text.trim()
+            logger.info("stream load 2pc out: ${out}, err: ${err}")
+            return parseCurlResult(out, err)
+        }
+
+        def assertLoadFailed = { def result ->
+            assertEquals(200, result[0])
+            def json = parseJson(result[1])
+            assertTrue("stream load should fail, body=${result[1]}", 
json.Status != "Success")
+        }
+
+        def assertLoadSuccess = { def result ->
+            assertEquals(200, result[0])
+            def json = parseJson(result[1])
+            assertEquals("Success", json.Status)
+            assertEquals(3, json.NumberTotalRows)
+            assertEquals(3, json.NumberLoadedRows)
+            return json
+        }
+
+        try {
+            try_sql("DROP USER ${tableUser}")
+            try_sql("DROP USER ${dbUser}")
+            sql """DROP DATABASE IF EXISTS ${dbName}"""
+            sql """CREATE USER '${tableUser}' IDENTIFIED BY '${pwd}'"""
+            sql """CREATE USER '${dbUser}' IDENTIFIED BY '${pwd}'"""
+            def clusters = sql """SHOW CLUSTERS"""
+            assertTrue(!clusters.isEmpty())
+            sql """GRANT USAGE_PRIV ON CLUSTER `${clusters[0][0]}` TO 
${tableUser}"""
+            sql """GRANT USAGE_PRIV ON CLUSTER `${clusters[0][0]}` TO 
${dbUser}"""
+
+            sql """CREATE DATABASE ${dbName}"""
+            sql """
+                CREATE TABLE ${dbName}.${tableName} (
+                    id BIGINT,
+                    username VARCHAR(20)
+                )
+                DISTRIBUTED BY HASH(id) BUCKETS 1
+                PROPERTIES ("replication_num" = "1")
+            """
+            sql """
+                CREATE TABLE ${dbName}.${otherTableName} (
+                    id BIGINT,
+                    username VARCHAR(20)
+                )
+                DISTRIBUTED BY HASH(id) BUCKETS 1
+                PROPERTIES ("replication_num" = "1")
+            """
+
+            assertLoadFailed(streamLoad(tableUser, beHttpAddress, tableName, 
"off_denied_before_grant",
+                    false, []))
+
+            sql """GRANT LOAD_PRIV ON ${dbName}.${tableName} TO ${tableUser}"""
+
+            assertLoadSuccess(streamLoad(tableUser, beHttpAddress, tableName, 
"off_table_grant_be",
+                    false, []))
+            assertLoadSuccess(streamLoad(tableUser, feHttpAddress, tableName, 
"off_table_grant_fe",
+                    true, []))
+            def prepared = assertLoadSuccess(streamLoad(tableUser, 
beHttpAddress, tableName,
+                    "off_table_grant_2pc", false, ["two_phase_commit:true"]))
+            def committed = streamLoad2pc(tableUser, tableName, 
prepared.TxnId, "commit")
+            assertEquals(200, committed[0])
+            assertEquals("Success", parseJson(committed[1]).status)
+
+            assertLoadFailed(streamLoad(tableUser, beHttpAddress, 
otherTableName,
+                    "off_denied_other_table", false, []))
+
+            sql """GRANT LOAD_PRIV ON ${dbName}.* TO ${dbUser}"""
+            assertLoadSuccess(streamLoad(dbUser, beHttpAddress, 
otherTableName, "off_db_grant_be",
+                    false, []))
+
+            def tableCount = sql """SELECT COUNT(*) FROM 
${dbName}.${tableName}"""
+            assertEquals(9, tableCount[0][0] as int)
+            def otherTableCount = sql """SELECT COUNT(*) FROM 
${dbName}.${otherTableName}"""
+            assertEquals(3, otherTableCount[0][0] as int)
+        } finally {
+            try_sql """DROP DATABASE IF EXISTS ${dbName}"""
+            try_sql("DROP USER ${tableUser}")
+            try_sql("DROP USER ${dbUser}")
+        }
+    }
+}
+
+suite("test_dml_stream_load_be_auth_on_docker", "docker,auth_call") {
+    def options = new ClusterOptions()
+    options.cloudMode = true
+    options.feNum = 1
+    options.beNum = 1
+    options.beConfigs.add("enable_all_http_auth=true")
+
+    docker(options) {
+        String suiteName = "test_dml_stream_load_be_auth_on_docker"
+        String tableUser = "${suiteName}_table_user"
+        String dbUser = "${suiteName}_db_user"
+        String pwd = "C123_567p"
+        String dbName = "${suiteName}_db"
+        String tableName = "${suiteName}_tb"
+        String otherTableName = "${suiteName}_other_tb"
+        String dataFile = 
"${context.file.parent}/../../data/auth_call/stream_load_data.csv"
+
+        def fe = cluster.getFeByIndex(1)
+        def be = cluster.getAllBackends(true).get(0)
+        String feHttpAddress = "${fe.host}:${fe.httpPort}"
+        String beHttpAddress = "${be.host}:${be.httpPort}"
+
+        def parseCurlResult = { String out, String err ->
+            def lines = out.readLines()
+            assertTrue("curl output should include http code, output=${out}, 
err=${err}", !lines.isEmpty())
+            def httpCode = lines.last() as int
+            def body = lines.size() == 1 ? "" : lines[0..-2].join("\n")
+            return [httpCode, body, err]
+        }
+
+        def streamLoad = { String authUser, String endpoint, String table, 
String label,
+                           boolean followRedirect, List extraHeaders ->
+            def command = [
+                    "curl", "--noproxy", "*", "-sS", "-w", "\n%{http_code}",
+                    "-u", "${authUser}:${pwd}",
+                    "-H", "label:${label}",
+                    "-H", "column_separator:,",
+            ]
+            if (followRedirect) {
+                command.add("--location-trusted")
+            }
+            extraHeaders.each { command.addAll(["-H", it]) }
+            command.addAll([
+                    "-T", dataFile,
+                    "http://${endpoint}/api/${dbName}/${table}/_stream_load";
+            ])
+            logger.info("stream load target: ${endpoint}, table: ${table}, 
label: ${label}, user: ${authUser}")
+            def process = command.execute()
+            process.waitForOrKill(7200000)
+            def out = process.text.trim()
+            def err = process.errorStream.text.trim()
+            logger.info("stream load out: ${out}, err: ${err}")
+            return parseCurlResult(out, err)
+        }
+
+        def streamLoad2pc = { String authUser, String table, def txnId, String 
txnOperation ->
+            def command = [
+                    "curl", "--noproxy", "*", "-sS", "-w", "\n%{http_code}",
+                    "-X", "PUT",
+                    "-u", "${authUser}:${pwd}",
+                    "-H", "txn_id:${txnId}",
+                    "-H", "txn_operation:${txnOperation}",
+                    
"http://${beHttpAddress}/api/${dbName}/${table}/_stream_load_2pc";
+            ]
+            logger.info("stream load 2pc target: ${beHttpAddress}, table: 
${table}, "
+                    + "txn operation: ${txnOperation}, user: ${authUser}")
+            def process = command.execute()
+            process.waitForOrKill(7200000)
+            def out = process.text.trim()
+            def err = process.errorStream.text.trim()
+            logger.info("stream load 2pc out: ${out}, err: ${err}")
+            return parseCurlResult(out, err)
+        }
+
+        def assertLoadFailed = { def result ->
+            assertEquals(200, result[0])
+            def json = parseJson(result[1])
+            assertTrue("stream load should fail, body=${result[1]}", 
json.Status != "Success")
+        }
+
+        def assertLoadSuccess = { def result ->
+            assertEquals(200, result[0])
+            def json = parseJson(result[1])
+            assertEquals("Success", json.Status)
+            assertEquals(3, json.NumberTotalRows)
+            assertEquals(3, json.NumberLoadedRows)
+            return json
+        }
+
+        try {
+            try_sql("DROP USER ${tableUser}")
+            try_sql("DROP USER ${dbUser}")
+            sql """DROP DATABASE IF EXISTS ${dbName}"""
+            sql """CREATE USER '${tableUser}' IDENTIFIED BY '${pwd}'"""
+            sql """CREATE USER '${dbUser}' IDENTIFIED BY '${pwd}'"""
+            def clusters = sql """SHOW CLUSTERS"""
+            assertTrue(!clusters.isEmpty())
+            sql """GRANT USAGE_PRIV ON CLUSTER `${clusters[0][0]}` TO 
${tableUser}"""
+            sql """GRANT USAGE_PRIV ON CLUSTER `${clusters[0][0]}` TO 
${dbUser}"""
+
+            sql """CREATE DATABASE ${dbName}"""
+            sql """
+                CREATE TABLE ${dbName}.${tableName} (
+                    id BIGINT,
+                    username VARCHAR(20)
+                )
+                DISTRIBUTED BY HASH(id) BUCKETS 1
+                PROPERTIES ("replication_num" = "1")
+            """
+            sql """
+                CREATE TABLE ${dbName}.${otherTableName} (
+                    id BIGINT,
+                    username VARCHAR(20)
+                )
+                DISTRIBUTED BY HASH(id) BUCKETS 1
+                PROPERTIES ("replication_num" = "1")
+            """
+
+            assertLoadFailed(streamLoad(tableUser, beHttpAddress, tableName, 
"on_denied_before_grant",
+                    false, []))
+
+            sql """GRANT LOAD_PRIV ON ${dbName}.${tableName} TO ${tableUser}"""
+
+            assertLoadSuccess(streamLoad(tableUser, beHttpAddress, tableName, 
"on_table_grant_be",
+                    false, []))
+            assertLoadSuccess(streamLoad(tableUser, feHttpAddress, tableName, 
"on_table_grant_fe",
+                    true, []))
+            def prepared = assertLoadSuccess(streamLoad(tableUser, 
beHttpAddress, tableName,
+                    "on_table_grant_2pc", false, ["two_phase_commit:true"]))
+            def committed = streamLoad2pc(tableUser, tableName, 
prepared.TxnId, "commit")
+            assertEquals(200, committed[0])
+            assertEquals("Success", parseJson(committed[1]).status)
+
+            assertLoadFailed(streamLoad(tableUser, beHttpAddress, 
otherTableName,
+                    "on_denied_other_table", false, []))
+
+            sql """GRANT LOAD_PRIV ON ${dbName}.* TO ${dbUser}"""
+            assertLoadSuccess(streamLoad(dbUser, beHttpAddress, 
otherTableName, "on_db_grant_be",
+                    false, []))
+
+            def tableCount = sql """SELECT COUNT(*) FROM 
${dbName}.${tableName}"""
+            assertEquals(9, tableCount[0][0] as int)
+            def otherTableCount = sql """SELECT COUNT(*) FROM 
${dbName}.${otherTableName}"""
+            assertEquals(3, otherTableCount[0][0] as int)
+        } finally {
+            try_sql """DROP DATABASE IF EXISTS ${dbName}"""
+            try_sql("DROP USER ${tableUser}")
+            try_sql("DROP USER ${dbUser}")
+        }
+    }
+}


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

Reply via email to