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 }