github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/hide_constants.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  //
    11  //
    12  
    13  package tree
    14  
    15  import (
    16  	"fmt"
    17  	"strings"
    18  )
    19  
    20  // formatNodeOrHideConstants recurses into a node for pretty-printing,
    21  // unless hideConstants is set in the flags and the node is a datum or
    22  // a literal.
    23  func (ctx *FmtCtx) formatNodeOrHideConstants(n NodeFormatter) {
    24  	if ctx.flags.HasFlags(FmtHideConstants) {
    25  		switch v := n.(type) {
    26  		case *ValuesClause:
    27  			v.formatHideConstants(ctx)
    28  			return
    29  		case *Tuple:
    30  			v.formatHideConstants(ctx)
    31  			return
    32  		case *Array:
    33  			v.formatHideConstants(ctx)
    34  			return
    35  		case *Placeholder:
    36  			// Placeholders should be printed as placeholder markers.
    37  			// Using always '$1' so we limit the amount of different
    38  			// fingerprints created.
    39  			ctx.WriteString("$1")
    40  			return
    41  		case *StrVal:
    42  			ctx.WriteString("'_'")
    43  			return
    44  		case Datum, Constant:
    45  			ctx.WriteByte('_')
    46  			return
    47  		}
    48  	}
    49  	n.Format(ctx)
    50  }
    51  
    52  // formatHideConstants shortens multi-valued VALUES clauses to a
    53  // VALUES clause with a single value.
    54  // e.g. VALUES (a,b,c), (d,e,f) -> VALUES (_, _, _), (__more__)
    55  func (node *ValuesClause) formatHideConstants(ctx *FmtCtx) {
    56  	ctx.WriteString("VALUES (")
    57  	node.Rows[0].formatHideConstants(ctx)
    58  	ctx.WriteByte(')')
    59  	if len(node.Rows) > 1 {
    60  		ctx.Printf(", (%s)", arityString(len(node.Rows)-1))
    61  	}
    62  }
    63  
    64  // formatHideConstants is used exclusively by ValuesClause above.
    65  // Other AST that contain Exprs do not use this.
    66  func (node *Exprs) formatHideConstants(ctx *FmtCtx) {
    67  	exprs := *node
    68  	if len(exprs) < 2 {
    69  		node.Format(ctx)
    70  		return
    71  	}
    72  
    73  	// First, determine if there are only literals/placeholders.
    74  	var i int
    75  	for i = 0; i < len(exprs); i++ {
    76  		switch exprs[i].(type) {
    77  		case Datum, Constant, *Placeholder:
    78  			continue
    79  		}
    80  		break
    81  	}
    82  	// If so, then use the special representation.
    83  	if i == len(exprs) {
    84  		// We copy the node to preserve the "row" boolean flag.
    85  		v2 := append(make(Exprs, 0, 3), exprs[:2]...)
    86  		if len(exprs) > 2 {
    87  			v2 = append(v2, arityIndicator(len(exprs)-2))
    88  		}
    89  		v2.Format(ctx)
    90  		return
    91  	}
    92  	node.Format(ctx)
    93  }
    94  
    95  // formatHideConstants formats tuples containing only literals or
    96  // placeholders and longer than 1 element as a tuple of its first
    97  // two elements, scrubbed.
    98  // e.g. (1)               -> (_)
    99  //
   100  //	(1, 2)            -> (_, _)
   101  //	(1, 2, 3)         -> (_, _, __more1_10__)
   102  //	ROW()             -> ROW()
   103  //	ROW($1, $2, $3)   -> ROW($1, $2, __more1_10__)
   104  //	(1+2, 2+3, 3+4)   -> (_ + _, _ + _, _ + _)
   105  //	(1+2, b, c)       -> (_ + _, b, c)
   106  func (node *Tuple) formatHideConstants(ctx *FmtCtx) {
   107  	if len(node.Exprs) < 2 {
   108  		node.Format(ctx)
   109  		return
   110  	}
   111  
   112  	// First, determine if there are only literals/placeholders.
   113  	var i int
   114  	for i = 0; i < len(node.Exprs); i++ {
   115  		switch node.Exprs[i].(type) {
   116  		case Datum, Constant, *Placeholder:
   117  			continue
   118  		}
   119  		break
   120  	}
   121  	// If so, then use the special representation.
   122  	if i == len(node.Exprs) {
   123  		// We copy the node to preserve the "row" boolean flag.
   124  		v2 := *node
   125  		v2.Exprs = append(make(Exprs, 0, 3), v2.Exprs[:2]...)
   126  		if len(node.Exprs) > 2 {
   127  			v2.Exprs = append(v2.Exprs, arityIndicator(len(node.Exprs)-2))
   128  			if len(node.Labels) > 2 {
   129  				v2.Labels = node.Labels[:2]
   130  			}
   131  		}
   132  		v2.Format(ctx)
   133  		return
   134  	}
   135  	node.Format(ctx)
   136  }
   137  
   138  // formatHideConstants formats array expressions containing only
   139  // literals or placeholders and longer than 1 element as an array
   140  // expression of its first two elements, scrubbed.
   141  // e.g. array[1]             -> array[_]
   142  //
   143  //	array[1, 2]          -> array[_, _]
   144  //	array[1, 2, 3]       -> array[_, _, __more1_10__]
   145  //	array[1+2, 2+3, 3+4] -> array[_ + _, _ + _, _ + _]
   146  func (node *Array) formatHideConstants(ctx *FmtCtx) {
   147  	if len(node.Exprs) < 2 {
   148  		node.Format(ctx)
   149  		return
   150  	}
   151  
   152  	// First, determine if there are only literals/placeholders.
   153  	var i int
   154  	for i = 0; i < len(node.Exprs); i++ {
   155  		switch node.Exprs[i].(type) {
   156  		case Datum, Constant, *Placeholder:
   157  			continue
   158  		}
   159  		break
   160  	}
   161  	// If so, then use the special representation.
   162  	if i == len(node.Exprs) {
   163  		// We copy the node to preserve the "row" boolean flag.
   164  		v2 := *node
   165  		v2.Exprs = append(make(Exprs, 0, 3), v2.Exprs[:2]...)
   166  		if len(node.Exprs) > 2 {
   167  			v2.Exprs = append(v2.Exprs, arityIndicator(len(node.Exprs)-2))
   168  		}
   169  		v2.Format(ctx)
   170  		return
   171  	}
   172  	node.Format(ctx)
   173  }
   174  
   175  func arityIndicator(n int) Expr {
   176  	return NewUnresolvedName(arityString(n))
   177  }
   178  
   179  func arityString(n int) string {
   180  	var v int
   181  	if n <= 10 {
   182  		return "__more1_10__"
   183  	}
   184  	if n <= 100 {
   185  		return "__more10_100__"
   186  	}
   187  	if n <= 1000 {
   188  		for v = 1; n >= 10; n /= 10 {
   189  			v = v * 10
   190  		}
   191  		v = v * n
   192  		return fmt.Sprintf("__more%d__", v)
   193  	}
   194  	return "__more1000_plus__"
   195  }
   196  
   197  func isArityIndicatorString(s string) bool {
   198  	return strings.HasPrefix(s, "__more")
   199  }