dongjoon-hyun opened a new pull request, #59739:
URL: https://github.com/apache/spark/pull/59739

   ### What changes were proposed in this pull request?
   
   This PR makes `PipelinesHandler.blockUnsupportedSqlCommand` check the 
statements under two parser wrappers at the top of a parsed plan.
   
   - `UnresolvedWith`: `AstBuilder.visitDmlStatement` puts a DML statement with 
a CTE prefix under `UnresolvedWith`, for example `WITH v AS (...) INSERT INTO t 
SELECT * FROM v`. A CTE prefix is allowed on `INSERT INTO`, `INSERT OVERWRITE 
[TABLE]`, `INSERT OVERWRITE [LOCAL] DIRECTORY`, `MERGE INTO`, `UPDATE`, `DELETE 
FROM`, and a multi-insert.
   - `Union`: `AstBuilder.visitMultiInsertQuery` builds a multi-insert with two 
or more `INSERT` clauses, `FROM src INSERT INTO t1 SELECT ... INSERT INTO t2 
SELECT ...`, as a `Union` of its `INSERT`s.
   
   The guard now applies the same check to the child of `UnresolvedWith` and to 
each child of `Union`. As a result, these statements fail with 
`UNSUPPORTED_PIPELINE_SPARK_SQL_COMMAND`, like the same statements without the 
wrapper. A read-only query with a CTE or a `UNION` still passes because its 
children are queries.
   
   This PR unwraps only these two wrappers instead of checking every node of 
the plan. The grammar allows a CTE prefix only on a query or a DML statement, 
and a CTE definition can only be a query. A multi-insert is the only statement 
that the parser builds as a `Union` of DML statements. So, apart from commands 
such as `EXPLAIN` that are already blocked, these are the only nodes that the 
parser puts above a DML statement.
   
   ### Why are the changes needed?
   
   The SDP guard checks only the class of the top node of the parsed plan. A 
DML statement with a CTE prefix and a multi-insert have a non-command node at 
the top, so the guard lets them pass. Outside a flow function, `spark.sql(...)` 
then runs them eagerly. For example, each of the following lines in a pipeline 
definition file inserts rows into `t` while the pipeline is being registered.
   
   ```python
   spark.sql("WITH v AS (SELECT 1 AS id) INSERT INTO t SELECT * FROM v")
   spark.sql("FROM (SELECT 1 AS id) s INSERT INTO t SELECT * INSERT INTO t 
SELECT *")
   ```
   
   Inside a flow function, the guard lets the same statements pass as well.
   
   This is the top-node limitation that was discussed in 
https://github.com/apache/spark/pull/59425 and left out of scope in 
https://github.com/apache/spark/pull/59719.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. These statements in `spark.sql(...)` of SDP now fail with the following 
error instead of modifying tables or directories. This is a bug fix for the SDP 
SQL guard, which has existed since Apache Spark 
[4.1.0](https://github.com/apache/spark/releases/tag/v4.1.0) (2025-12-11).
   
   ```
   [UNSUPPORTED_PIPELINE_SPARK_SQL_COMMAND] 'UnresolvedInsert' is not supported 
in spark.sql("...") API in Spark Declarative Pipeline. SQLSTATE: 0A000
   ```
   
   The error names the class of the wrapped statement, such as 
`UnresolvedInsert` or `MergeIntoTable`, like the error for the same statement 
without the wrapper.
   
   ### How was this patch tested?
   
   Pass the CIs with the newly added test cases in `PythonPipelineSuite`.
   
   - `unsupportedSqlCommandList` has five more statements: `WITH ... INSERT 
INTO`, `WITH ... MERGE INTO`, `WITH ... UPDATE`, `WITH ... DELETE FROM`, and a 
multi-insert. Like the existing entries, each of them runs both outside and 
inside a pipeline flow function.
   - `supportedSqlCommandList` has a read-only CTE query and a `UNION ALL` 
query, to make sure that the new check does not block them.
   
   Without the fix, the 10 new unsupported test cases fail. Outside a flow 
function, the statement passes the guard and then fails with 
`TABLE_OR_VIEW_NOT_FOUND` instead of `UNSUPPORTED_PIPELINE_SPARK_SQL_COMMAND`. 
Inside a flow function, no exception is thrown. The 4 new supported test cases 
pass with and without the fix.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Opus 5.5


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