codeant-ai-for-open-source[bot] commented on code in PR #42412:
URL: https://github.com/apache/superset/pull/42412#discussion_r3662917650


##########
superset/commands/streaming_export/base.py:
##########
@@ -219,19 +218,44 @@ def _execute_query_and_stream(
         delimiter = csv_export_config.get("sep", ",")
         decimal_separator = csv_export_config.get("decimal", ".")
 
+        # Apply SQL mutations (e.g. SQL_QUERY_MUTATOR config hook) before
+        # execution.  All non-streaming paths go through this — the streaming
+        # path was originally skipping it, which left trailing semicolons
+        # unstripped for engines like Trino that reject them.
+        sql = database.mutate_sql_based_on_config(sql)
+
         with db.session(future=True) as session:
             # Merge database to prevent DetachedInstanceError
             merged_database = session.merge(database)
 
-            with merged_database.get_sqla_engine(
-                catalog=catalog, schema=schema
-            ) as engine:
-                with engine.connect() as connection:
-                    result_proxy = connection.execution_options(
-                        stream_results=True
-                    ).execute(text(sql))
-
-                    columns = list(result_proxy.keys())
+            # Use get_raw_connection() instead of get_sqla_engine() directly.
+            # This is critical for:
+            # 1. User impersonation — get_raw_connection() goes through the
+            #    ENGINE_CONTEXT_MANAGER which applies impersonate_user settings
+            #    (e.g. X-Trino-User header).  Without this, all streaming CSV
+            #    exports run as the service principal, breaking audit trails
+            #    and potentially bypassing per-user authorization (Ranger, OPA,
+            #    RLS views).
+            # 2. SSH tunnels — get_raw_connection() sets up SSH tunnels if
+            #    configured on the database.
+            # 3. OAuth2 — get_raw_connection() wraps execution in
+            #    check_for_oauth2() context.
+            with closing(
+                merged_database.get_raw_connection(catalog=catalog, 
schema=schema)
+            ) as conn:
+                cursor = conn.cursor()
+                # Set cursor.arraysize to control the batch size for 
fetchmany().
+                # This ensures DBAPI drivers (Trino, PostgreSQL, etc.) fetch
+                # rows in manageable chunks instead of buffering the entire
+                # result set client-side.
+                cursor.arraysize = limit

Review Comment:
   **Suggestion:** `limit` is `None` for chart exports and unlimited SQL Lab 
exports, but DBAPI `cursor.arraysize` requires an integer. This assignment can 
raise a driver-specific type error for every unlimited streaming export, and it 
is unnecessary because `_process_rows()` already passes `self._chunk_size` 
explicitly to `fetchmany()`. [type error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Unlimited chart CSV exports can fail during cursor setup.
   - ❌ Unlimited SQL Lab exports can fail during cursor setup.
   - ⚠️ Driver behavior becomes database-dependent.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Request a chart streaming CSV export through 
superset/charts/data/api.py:756-765;
   StreamingCSVExportCommand._get_row_limit() explicitly returns None for every 
chart export
   at superset/commands/chart/data/streaming_export_command.py:76-83.
   
   2. After entering the raw connection context, execution reaches
   BaseStreamingCSVExportCommand._execute_query_and_stream() at
   superset/commands/streaming_export/base.py:194.
   
   3. The code assigns None to cursor.arraysize at
   superset/commands/streaming_export/base.py:251. DBAPI cursor arraysize is an 
integer
   fetch-size attribute, and drivers may reject None with a TypeError or 
equivalent driver
   error.
   
   4. The subsequent _process_rows() call at base.py:281-283 already invokes
   fetchmany(self._chunk_size), so arraysize is not needed to implement the 
configured batch
   size. The export therefore fails for unlimited chart exports before rows are 
streamed; SQL
   Lab exports with select_sql set also return None from
   superset/commands/sql_lab/streaming_export_command.py:119-127.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=a449922712ac4e209ee00944ef0badd8&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=a449922712ac4e209ee00944ef0badd8&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/commands/streaming_export/base.py
   **Line:** 251:251
   **Comment:**
        *Type Error: `limit` is `None` for chart exports and unlimited SQL Lab 
exports, but DBAPI `cursor.arraysize` requires an integer. This assignment can 
raise a driver-specific type error for every unlimited streaming export, and it 
is unnecessary because `_process_rows()` already passes `self._chunk_size` 
explicitly to `fetchmany()`.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42412&comment_hash=f92dccbf585eecc59380d1ef20fa4a92a181a3692a9060f6cae6b98760e05a9e&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42412&comment_hash=f92dccbf585eecc59380d1ef20fa4a92a181a3692a9060f6cae6b98760e05a9e&reaction=dislike'>👎</a>



##########
superset/commands/streaming_export/base.py:
##########
@@ -219,19 +218,44 @@ def _execute_query_and_stream(
         delimiter = csv_export_config.get("sep", ",")
         decimal_separator = csv_export_config.get("decimal", ".")
 
+        # Apply SQL mutations (e.g. SQL_QUERY_MUTATOR config hook) before
+        # execution.  All non-streaming paths go through this — the streaming
+        # path was originally skipping it, which left trailing semicolons
+        # unstripped for engines like Trino that reject them.
+        sql = database.mutate_sql_based_on_config(sql)

Review Comment:
   **Suggestion:** The SQL mutator receives the original database object before 
it is merged into the active session. Streaming generators run after the 
request session may have ended, so a configured `SQL_QUERY_MUTATOR` that reads 
a lazy or session-bound database attribute can raise `DetachedInstanceError`. 
Merge the database first and invoke the mutator with the merged instance. 
[stale reference]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Configured database-aware SQL mutators can fail during exports.
   - ⚠️ Streaming response timing exposes detached ORM state.
   - ⚠️ Affected SQL mutation and audit customization paths.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start a chart or SQL Lab streaming export through 
superset/charts/data/api.py:756-765
   or superset/sqllab/api.py:417-435. BaseStreamingCSVExportCommand.run() 
captures the
   database and returns a generator at 
superset/commands/streaming_export/base.py:129-145, so
   query execution occurs during response streaming rather than during command 
construction.
   
   2. Configure SQL_QUERY_MUTATOR with a function that uses the supplied 
database keyword
   argument, which is explicitly passed by 
Database.mutate_sql_based_on_config() at
   superset/models/core.py:787-805.
   
   3. When the generator reaches 
superset/commands/streaming_export/base.py:225, it invokes
   the mutator on the original database object before entering 
db.session(future=True) and
   before session.merge(database) at base.py:227-230.
   
   4. Because the generator runs after the original request work may have 
released or
   detached its ORM session, a mutator that reads a deferred or session-bound 
Database
   attribute can raise DetachedInstanceError. The merged instance is available 
at base.py:229
   and should be used for mutation before opening the connection.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=5dee3a490c6f4cd39fe13668d095ae61&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=5dee3a490c6f4cd39fe13668d095ae61&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/commands/streaming_export/base.py
   **Line:** 225:225
   **Comment:**
        *Stale Reference: The SQL mutator receives the original database object 
before it is merged into the active session. Streaming generators run after the 
request session may have ended, so a configured `SQL_QUERY_MUTATOR` that reads 
a lazy or session-bound database attribute can raise `DetachedInstanceError`. 
Merge the database first and invoke the mutator with the merged instance.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42412&comment_hash=8e868db8d85d33066d37c35ad60a1e711e6022287859bb5e49ffcd1c117371d3&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42412&comment_hash=8e868db8d85d33066d37c35ad60a1e711e6022287859bb5e49ffcd1c117371d3&reaction=dislike'>👎</a>



-- 
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