@@ -154,4 +154,121 @@ class GlutenSQLQuerySuite extends SQLQuerySuite with GlutenSQLTestsTrait {
154154 assert(inputOutputPairs.map(_._1).sum == numRows)
155155 }
156156 }
157+
158+ testGluten(" SPARK-47939: Explain should work with parameterized queries" ) {
159+ def checkQueryPlan (df : DataFrame , plan : String ): Unit = assert(
160+ df.collect()
161+ .map(_.getString(0 ))
162+ .map(_.replaceAll(" #[0-9]+" , " #N" ))
163+ // Remove the backend keyword in c2r/r2c.
164+ .map(_.replaceAll(" [A-Za-z]*ColumnarToRow" , " ColumnarToRow" ))
165+ .map(_.replaceAll(" RowTo[A-Za-z]*Columnar" , " RowToColumnar" ))
166+ === Array (plan.stripMargin)
167+ )
168+
169+ checkQueryPlan(
170+ spark.sql(" explain select ?" , Array (1 )),
171+ """ == Physical Plan ==
172+ |ColumnarToRow
173+ |+- ^(1) ProjectExecTransformer [1 AS 1#N]
174+ | +- ^(1) InputIteratorTransformer[]
175+ | +- RowToColumnar
176+ | +- *(1) Scan OneRowRelation[]
177+ |
178+ |"""
179+ )
180+ checkQueryPlan(
181+ spark.sql(" explain select :first" , Map (" first" -> 1 )),
182+ """ == Physical Plan ==
183+ |ColumnarToRow
184+ |+- ^(2) ProjectExecTransformer [1 AS 1#N]
185+ | +- ^(2) InputIteratorTransformer[]
186+ | +- RowToColumnar
187+ | +- *(1) Scan OneRowRelation[]
188+ |
189+ |"""
190+ )
191+
192+ checkQueryPlan(
193+ spark.sql(" explain explain explain select ?" , Array (1 )),
194+ """ == Physical Plan ==
195+ |Execute ExplainCommand
196+ | +- ExplainCommand ExplainCommand 'PosParameterizedQuery [1], SimpleMode, SimpleMode
197+
198+ |"""
199+ )
200+ checkQueryPlan(
201+ spark.sql(" explain explain explain select :first" , Map (" first" -> 1 )),
202+ // scalastyle:off
203+ """ == Physical Plan ==
204+ |Execute ExplainCommand
205+ | +- ExplainCommand ExplainCommand 'NameParameterizedQuery [first], [1], SimpleMode, SimpleMode
206+
207+ |"""
208+ // scalastyle:on
209+ )
210+
211+ checkQueryPlan(
212+ spark.sql(" explain describe select ?" , Array (1 )),
213+ """ == Physical Plan ==
214+ |Execute DescribeQueryCommand
215+ | +- DescribeQueryCommand select ?
216+
217+ |"""
218+ )
219+ checkQueryPlan(
220+ spark.sql(" explain describe select :first" , Map (" first" -> 1 )),
221+ """ == Physical Plan ==
222+ |Execute DescribeQueryCommand
223+ | +- DescribeQueryCommand select :first
224+
225+ |"""
226+ )
227+
228+ checkQueryPlan(
229+ spark.sql(" explain extended select * from values (?, ?) t(x, y)" , Array (1 , " a" )),
230+ """ == Parsed Logical Plan ==
231+ |'PosParameterizedQuery [1, a]
232+ |+- 'Project [*]
233+ | +- 'SubqueryAlias t
234+ | +- 'UnresolvedInlineTable [x, y], [[posparameter(39), posparameter(42)]]
235+
236+ |== Analyzed Logical Plan ==
237+ |x: int, y: string
238+ |Project [x#N, y#N]
239+ |+- SubqueryAlias t
240+ | +- LocalRelation [x#N, y#N]
241+
242+ |== Optimized Logical Plan ==
243+ |LocalRelation [x#N, y#N]
244+
245+ |== Physical Plan ==
246+ |LocalTableScan [x#N, y#N]
247+ |"""
248+ )
249+ checkQueryPlan(
250+ spark.sql(
251+ " explain extended select * from values (:first, :second) t(x, y)" ,
252+ Map (" first" -> 1 , " second" -> " a" )
253+ ),
254+ """ == Parsed Logical Plan ==
255+ |'NameParameterizedQuery [first, second], [1, a]
256+ |+- 'Project [*]
257+ | +- 'SubqueryAlias t
258+ | +- 'UnresolvedInlineTable [x, y], [[namedparameter(first), namedparameter(second)]]
259+
260+ |== Analyzed Logical Plan ==
261+ |x: int, y: string
262+ |Project [x#N, y#N]
263+ |+- SubqueryAlias t
264+ | +- LocalRelation [x#N, y#N]
265+
266+ |== Optimized Logical Plan ==
267+ |LocalRelation [x#N, y#N]
268+
269+ |== Physical Plan ==
270+ |LocalTableScan [x#N, y#N]
271+ |"""
272+ )
273+ }
157274}
0 commit comments