@@ -211,6 +211,31 @@ func isSimpleLiteralOrNegation(e ast.Expression) bool {
211211 return false
212212}
213213
214+ // isSimpleLiteralOrNestedLiteral checks if an expression is a literal (including nested tuples/arrays of literals)
215+ // Returns false for complex expressions like subqueries, function calls, identifiers, etc.
216+ func isSimpleLiteralOrNestedLiteral (e ast.Expression ) bool {
217+ if lit , ok := e .(* ast.Literal ); ok {
218+ // For nested arrays/tuples, recursively check if all elements are also literals
219+ if lit .Type == ast .LiteralArray || lit .Type == ast .LiteralTuple {
220+ if exprs , ok := lit .Value .([]ast.Expression ); ok {
221+ for _ , elem := range exprs {
222+ if ! isSimpleLiteralOrNestedLiteral (elem ) {
223+ return false
224+ }
225+ }
226+ }
227+ }
228+ return true
229+ }
230+ // Unary minus of a literal integer/float is also simple (negative number)
231+ if unary , ok := e .(* ast.UnaryExpr ); ok && unary .Op == "-" {
232+ if lit , ok := unary .Operand .(* ast.Literal ); ok {
233+ return lit .Type == ast .LiteralInteger || lit .Type == ast .LiteralFloat
234+ }
235+ }
236+ return false
237+ }
238+
214239// containsOnlyArraysOrTuples checks if a slice of expressions contains
215240// only array or tuple literals (including empty arrays).
216241// Returns true if the slice is empty or contains only arrays/tuples.
@@ -952,16 +977,39 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string,
952977 // When name is empty, don't show the alias part
953978 switch e := n .Query .(type ) {
954979 case * ast.Literal :
955- // Empty tuples should be rendered as Function tuple, not Literal
980+ // Tuples containing complex expressions (subqueries, function calls, etc) should be rendered as Function tuple
981+ // But tuples of simple literals (including nested tuples of literals) stay as Literal
956982 if e .Type == ast .LiteralTuple {
957- if exprs , ok := e .Value .([]ast.Expression ); ok && len (exprs ) == 0 {
958- if n .Name != "" {
959- fmt .Fprintf (sb , "%sFunction tuple (alias %s) (children %d)\n " , indent , n .Name , 1 )
983+ if exprs , ok := e .Value .([]ast.Expression ); ok {
984+ needsFunctionFormat := false
985+ // Empty tuples always use Function tuple format
986+ if len (exprs ) == 0 {
987+ needsFunctionFormat = true
960988 } else {
961- fmt .Fprintf (sb , "%sFunction tuple (children %d)\n " , indent , 1 )
989+ for _ , expr := range exprs {
990+ // Check if any element is a truly complex expression (not just a literal)
991+ if ! isSimpleLiteralOrNestedLiteral (expr ) {
992+ needsFunctionFormat = true
993+ break
994+ }
995+ }
996+ }
997+ if needsFunctionFormat {
998+ if n .Name != "" {
999+ fmt .Fprintf (sb , "%sFunction tuple (alias %s) (children %d)\n " , indent , n .Name , 1 )
1000+ } else {
1001+ fmt .Fprintf (sb , "%sFunction tuple (children %d)\n " , indent , 1 )
1002+ }
1003+ if len (exprs ) > 0 {
1004+ fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , len (exprs ))
1005+ } else {
1006+ fmt .Fprintf (sb , "%s ExpressionList\n " , indent )
1007+ }
1008+ for _ , expr := range exprs {
1009+ Node (sb , expr , depth + 2 )
1010+ }
1011+ return
9621012 }
963- fmt .Fprintf (sb , "%s ExpressionList\n " , indent )
964- return
9651013 }
9661014 }
9671015 // Arrays containing non-literal expressions should be rendered as Function array
@@ -1064,6 +1112,36 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string,
10641112 explainArrayAccessWithAlias (sb , e , n .Name , indent , depth )
10651113 case * ast.BetweenExpr :
10661114 explainBetweenExprWithAlias (sb , e , n .Name , indent , depth )
1115+ case * ast.UnaryExpr :
1116+ // For unary minus with numeric literal, output as negative literal with alias
1117+ if e .Op == "-" {
1118+ if lit , ok := e .Operand .(* ast.Literal ); ok && (lit .Type == ast .LiteralInteger || lit .Type == ast .LiteralFloat ) {
1119+ // Format as negative literal
1120+ negLit := & ast.Literal {
1121+ Position : lit .Position ,
1122+ Type : lit .Type ,
1123+ Value : lit .Value ,
1124+ }
1125+ if n .Name != "" {
1126+ fmt .Fprintf (sb , "%sLiteral %s (alias %s)\n " , indent , formatNegativeLiteral (negLit ), n .Name )
1127+ } else {
1128+ fmt .Fprintf (sb , "%sLiteral %s\n " , indent , formatNegativeLiteral (negLit ))
1129+ }
1130+ return
1131+ }
1132+ }
1133+ // For other unary expressions, output as function
1134+ fnName := "negate"
1135+ if e .Op == "NOT" {
1136+ fnName = "not"
1137+ }
1138+ if n .Name != "" {
1139+ fmt .Fprintf (sb , "%sFunction %s (alias %s) (children %d)\n " , indent , fnName , n .Name , 1 )
1140+ } else {
1141+ fmt .Fprintf (sb , "%sFunction %s (children %d)\n " , indent , fnName , 1 )
1142+ }
1143+ fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , 1 )
1144+ Node (sb , e .Operand , depth + 2 )
10671145 default :
10681146 // For other types, just output the expression (alias may be lost)
10691147 Node (sb , n .Query , depth )
0 commit comments