@@ -61,7 +61,7 @@ func extractWithClause(stmt ast.Statement) []ast.Expression {
6161}
6262
6363// explainSelectQueryWithInheritedWith outputs a SELECT with an inherited WITH clause
64- // The inherited WITH clause is output AFTER the columns (not before, like a regular WITH )
64+ // The inherited WITH clause is output at the END of children (after columns and tables )
6565func explainSelectQueryWithInheritedWith (sb * strings.Builder , stmt ast.Statement , inheritedWith []ast.Expression , depth int ) {
6666 sq , ok := stmt .(* ast.SelectQuery )
6767 if ! ok {
@@ -76,23 +76,17 @@ func explainSelectQueryWithInheritedWith(sb *strings.Builder, stmt ast.Statement
7676 return
7777 }
7878
79- // Output SelectQuery with inherited WITH clause after columns
79+ // Output SelectQuery with inherited WITH clause at the end
8080 indent := strings .Repeat (" " , depth )
8181 children := countSelectQueryChildren (sq ) + 1 // +1 for inherited WITH clause
8282 fmt .Fprintf (sb , "%sSelectQuery (children %d)\n " , indent , children )
8383
84- // Columns (ExpressionList) - output BEFORE inherited WITH
84+ // Columns (ExpressionList) - output first
8585 fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , len (sq .Columns ))
8686 for _ , col := range sq .Columns {
8787 Node (sb , col , depth + 2 )
8888 }
8989
90- // Inherited WITH clause (ExpressionList) - output AFTER columns
91- fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , len (inheritedWith ))
92- for _ , w := range inheritedWith {
93- Node (sb , w , depth + 2 )
94- }
95-
9690 // FROM (including ARRAY JOIN as part of TablesInSelectQuery)
9791 if sq .From != nil || sq .ArrayJoin != nil {
9892 TablesWithArrayJoin (sb , sq .From , sq .ArrayJoin , depth + 1 )
@@ -180,6 +174,105 @@ func explainSelectQueryWithInheritedWith(sb *strings.Builder, stmt ast.Statement
180174 if sq .Top != nil {
181175 Node (sb , sq .Top , depth + 1 )
182176 }
177+
178+ // Inherited WITH clause (ExpressionList) - output at the END
179+ fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , len (inheritedWith ))
180+ for _ , w := range inheritedWith {
181+ Node (sb , w , depth + 2 )
182+ }
183+ }
184+
185+ // ExplainSelectWithInheritedWith recursively explains a select statement with inherited WITH clause
186+ // This is used for WITH ... INSERT ... SELECT where the WITH clause belongs to the INSERT
187+ // but needs to be output at the end of each SelectQuery in the tree
188+ func ExplainSelectWithInheritedWith (sb * strings.Builder , stmt ast.Statement , inheritedWith []ast.Expression , depth int ) {
189+ switch s := stmt .(type ) {
190+ case * ast.SelectWithUnionQuery :
191+ explainSelectWithUnionQueryWithInheritedWith (sb , s , inheritedWith , depth )
192+ case * ast.SelectIntersectExceptQuery :
193+ explainSelectIntersectExceptQueryWithInheritedWith (sb , s , inheritedWith , depth )
194+ case * ast.SelectQuery :
195+ explainSelectQueryWithInheritedWith (sb , s , inheritedWith , depth )
196+ default :
197+ Node (sb , stmt , depth )
198+ }
199+ }
200+
201+ // explainSelectWithUnionQueryWithInheritedWith explains a SelectWithUnionQuery with inherited WITH
202+ func explainSelectWithUnionQueryWithInheritedWith (sb * strings.Builder , n * ast.SelectWithUnionQuery , inheritedWith []ast.Expression , depth int ) {
203+ if n == nil {
204+ return
205+ }
206+ indent := strings .Repeat (" " , depth )
207+ children := countSelectUnionChildren (n )
208+ fmt .Fprintf (sb , "%sSelectWithUnionQuery (children %d)\n " , indent , children )
209+
210+ selects := simplifyUnionSelects (n .Selects )
211+ fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , len (selects ))
212+ for _ , sel := range selects {
213+ ExplainSelectWithInheritedWith (sb , sel , inheritedWith , depth + 2 )
214+ }
215+
216+ // INTO OUTFILE clause
217+ for _ , sel := range n .Selects {
218+ if sq , ok := sel .(* ast.SelectQuery ); ok && sq .IntoOutfile != nil {
219+ fmt .Fprintf (sb , "%s Literal \\ '%s\\ '\n " , indent , sq .IntoOutfile .Filename )
220+ break
221+ }
222+ }
223+ // SETTINGS before FORMAT
224+ if n .SettingsBeforeFormat && len (n .Settings ) > 0 {
225+ fmt .Fprintf (sb , "%s Set\n " , indent )
226+ }
227+ // FORMAT clause - check individual SelectQuery nodes
228+ for _ , sel := range n .Selects {
229+ if sq , ok := sel .(* ast.SelectQuery ); ok && sq .Format != nil {
230+ Node (sb , sq .Format , depth + 1 )
231+ break
232+ }
233+ }
234+ // SETTINGS after FORMAT
235+ if n .SettingsAfterFormat && len (n .Settings ) > 0 {
236+ fmt .Fprintf (sb , "%s Set\n " , indent )
237+ } else {
238+ for _ , sel := range n .Selects {
239+ if sq , ok := sel .(* ast.SelectQuery ); ok && sq .SettingsAfterFormat && len (sq .Settings ) > 0 {
240+ fmt .Fprintf (sb , "%s Set\n " , indent )
241+ break
242+ }
243+ }
244+ }
245+ }
246+
247+ // explainSelectIntersectExceptQueryWithInheritedWith explains a SelectIntersectExceptQuery with inherited WITH
248+ func explainSelectIntersectExceptQueryWithInheritedWith (sb * strings.Builder , n * ast.SelectIntersectExceptQuery , inheritedWith []ast.Expression , depth int ) {
249+ indent := strings .Repeat (" " , depth )
250+ fmt .Fprintf (sb , "%sSelectIntersectExceptQuery (children %d)\n " , indent , len (n .Selects ))
251+
252+ // Check if EXCEPT is present - affects how first operand is wrapped
253+ hasExcept := false
254+ for _ , op := range n .Operators {
255+ if strings .HasPrefix (op , "EXCEPT" ) {
256+ hasExcept = true
257+ break
258+ }
259+ }
260+
261+ for i , sel := range n .Selects {
262+ if hasExcept && i == 0 {
263+ // Wrap first operand in SelectWithUnionQuery format
264+ if _ , isUnion := sel .(* ast.SelectWithUnionQuery ); isUnion {
265+ ExplainSelectWithInheritedWith (sb , sel , inheritedWith , depth + 1 )
266+ } else {
267+ childIndent := strings .Repeat (" " , depth + 1 )
268+ fmt .Fprintf (sb , "%sSelectWithUnionQuery (children 1)\n " , childIndent )
269+ fmt .Fprintf (sb , "%s ExpressionList (children 1)\n " , childIndent )
270+ ExplainSelectWithInheritedWith (sb , sel , inheritedWith , depth + 3 )
271+ }
272+ } else {
273+ ExplainSelectWithInheritedWith (sb , sel , inheritedWith , depth + 1 )
274+ }
275+ }
183276}
184277
185278func explainSelectWithUnionQuery (sb * strings.Builder , n * ast.SelectWithUnionQuery , indent string , depth int ) {
0 commit comments