@@ -248,98 +248,9 @@ func countSelectUnionChildren(n *ast.SelectWithUnionQuery) int {
248248 return count
249249}
250250
251- // simplifyUnionSelects implements ClickHouse's UNION ALL optimization:
252- // When all SELECT queries in a UNION have identical expressions (ignoring aliases)
253- // but different aliases, only the first SELECT is returned.
254- // This only applies when ALL columns in ALL SELECTs have explicit aliases.
255- // If aliases are the same across all SELECTs, or if any column lacks an alias, all are kept.
251+ // simplifyUnionSelects returns all SELECT statements in a UNION.
252+ // ClickHouse does not simplify UNION ALL queries in EXPLAIN AST output.
256253func simplifyUnionSelects (selects []ast.Statement ) []ast.Statement {
257- if len (selects ) <= 1 {
258- return selects
259- }
260-
261- // Check if all are simple SelectQuery with only literal columns
262- var queries []* ast.SelectQuery
263- for _ , sel := range selects {
264- sq , ok := sel .(* ast.SelectQuery )
265- if ! ok {
266- // Not a simple SelectQuery, can't simplify
267- return selects
268- }
269- // Only handle simple SELECT with just columns, no FROM/WHERE/etc.
270- if sq .From != nil || sq .Where != nil || sq .GroupBy != nil ||
271- sq .Having != nil || sq .OrderBy != nil || len (sq .With ) > 0 {
272- return selects
273- }
274- queries = append (queries , sq )
275- }
276-
277- // Check if all have the same number of columns
278- numCols := len (queries [0 ].Columns )
279- for _ , q := range queries [1 :] {
280- if len (q .Columns ) != numCols {
281- return selects
282- }
283- }
284-
285- // Check if columns are all literals with aliases
286- // and compare expressions (without aliases) and aliases separately
287- allSameAliases := true
288- allSameExprs := true
289- allHaveAliases := true
290-
291- for colIdx := 0 ; colIdx < numCols ; colIdx ++ {
292- firstAlias := ""
293- firstExpr := ""
294-
295- for i , q := range queries {
296- col := q .Columns [colIdx ]
297- alias := ""
298- exprStr := ""
299- hasAlias := false
300-
301- switch c := col .(type ) {
302- case * ast.AliasedExpr :
303- alias = c .Alias
304- hasAlias = c .Alias != ""
305- // Get string representation of the expression
306- if lit , ok := c .Expr .(* ast.Literal ); ok {
307- exprStr = fmt .Sprintf ("%v" , lit .Value )
308- } else {
309- // Non-literal expression, can't simplify
310- return selects
311- }
312- case * ast.Literal :
313- exprStr = fmt .Sprintf ("%v" , c .Value )
314- hasAlias = false
315- default :
316- // Not a simple literal or aliased literal
317- return selects
318- }
319-
320- if ! hasAlias {
321- allHaveAliases = false
322- }
323-
324- if i == 0 {
325- firstAlias = alias
326- firstExpr = exprStr
327- } else {
328- if alias != firstAlias {
329- allSameAliases = false
330- }
331- if exprStr != firstExpr {
332- allSameExprs = false
333- }
334- }
335- }
336- }
337-
338- // If expressions are the same, all have aliases, but aliases differ, return only first SELECT
339- if allSameExprs && allHaveAliases && ! allSameAliases {
340- return selects [:1 ]
341- }
342-
343254 return selects
344255}
345256
0 commit comments