github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/format/format.go (about) 1 // Copyright (c) 2014 The sortutil Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSES/STRUTIL-LICENSE file. 4 5 // Copyright 2015 PingCAP, Inc. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package format 19 20 import ( 21 "bytes" 22 "fmt" 23 "io" 24 "strings" 25 ) 26 27 const ( 28 st0 = iota 29 stBOL 30 stPERC 31 stBOLPERC 32 ) 33 34 // Formatter is an io.Writer extended formatter by a fmt.Printf like function Format. 35 type Formatter interface { 36 io.Writer 37 Format(format string, args ...interface{}) (n int, errno error) 38 } 39 40 type indentFormatter struct { 41 io.Writer 42 indent []byte 43 indentLevel int 44 state int 45 } 46 47 var replace = map[rune]string{ 48 '\000': "\\0", 49 '\'': "''", 50 '\n': "\\n", 51 '\r': "\\r", 52 } 53 54 // IndentFormatter returns a new Formatter which interprets %i and %u in the 55 // Format() formats string as indent and unindent commands. The commands can 56 // nest. The Formatter writes to io.Writer 'w' and inserts one 'indent' 57 // string per current indent level value. 58 // Behaviour of commands reaching negative indent levels is undefined. 59 // 60 // IndentFormatter(os.Stdout, "\t").Format("abc%d%%e%i\nx\ny\n%uz\n", 3) 61 // 62 // output: 63 // 64 // abc3%e 65 // x 66 // y 67 // z 68 // 69 // The Go quoted string literal form of the above is: 70 // 71 // "abc%%e\n\tx\n\tx\nz\n" 72 // 73 // The commands can be scattered between separate invocations of Format(), 74 // i.e. the formatter keeps track of the indent level and knows if it is 75 // positioned on start of a line and should emit indentation(s). 76 // The same output as above can be produced by e.g.: 77 // 78 // f := IndentFormatter(os.Stdout, " ") 79 // f.Format("abc%d%%e%i\nx\n", 3) 80 // f.Format("y\n%uz\n") 81 func IndentFormatter(w io.Writer, indent string) Formatter { 82 return &indentFormatter{w, []byte(indent), 0, stBOL} 83 } 84 85 func (f *indentFormatter) format(flat bool, format string, args ...interface{}) (n int, errno error) { 86 var buf = make([]byte, 0) 87 for i := 0; i < len(format); i++ { 88 c := format[i] 89 switch f.state { 90 case st0: 91 switch c { 92 case '\n': 93 cc := c 94 if flat && f.indentLevel != 0 { 95 cc = ' ' 96 } 97 buf = append(buf, cc) 98 f.state = stBOL 99 case '%': 100 f.state = stPERC 101 default: 102 buf = append(buf, c) 103 } 104 case stBOL: 105 switch c { 106 case '\n': 107 cc := c 108 if flat && f.indentLevel != 0 { 109 cc = ' ' 110 } 111 buf = append(buf, cc) 112 case '%': 113 f.state = stBOLPERC 114 default: 115 if !flat { 116 for i := 0; i < f.indentLevel; i++ { 117 buf = append(buf, f.indent...) 118 } 119 } 120 buf = append(buf, c) 121 f.state = st0 122 } 123 case stBOLPERC: 124 switch c { 125 case 'i': 126 f.indentLevel++ 127 f.state = stBOL 128 case 'u': 129 f.indentLevel-- 130 f.state = stBOL 131 default: 132 if !flat { 133 for i := 0; i < f.indentLevel; i++ { 134 buf = append(buf, f.indent...) 135 } 136 } 137 buf = append(buf, '%', c) 138 f.state = st0 139 } 140 case stPERC: 141 switch c { 142 case 'i': 143 f.indentLevel++ 144 f.state = st0 145 case 'u': 146 f.indentLevel-- 147 f.state = st0 148 default: 149 buf = append(buf, '%', c) 150 f.state = st0 151 } 152 default: 153 panic("unexpected state") 154 } 155 } 156 switch f.state { 157 case stPERC, stBOLPERC: 158 buf = append(buf, '%') 159 } 160 return fmt.Fprintf(f, string(buf), args...) 161 } 162 163 // Format implements Format interface. 164 func (f *indentFormatter) Format(format string, args ...interface{}) (n int, errno error) { 165 return f.format(false, format, args...) 166 } 167 168 type flatFormatter indentFormatter 169 170 // FlatFormatter returns a newly created Formatter with the same functionality as the one returned 171 // by IndentFormatter except it allows a newline in the 'format' string argument of Format 172 // to pass through if the indent level is current zero. 173 // 174 // If the indent level is non-zero then such new lines are changed to a space character. 175 // There is no indent string, the %i and %u format verbs are used solely to determine the indent level. 176 // 177 // The FlatFormatter is intended for flattening of normally nested structure textual representation to 178 // a one top level structure per line form. 179 // 180 // FlatFormatter(os.Stdout, " ").Format("abc%d%%e%i\nx\ny\n%uz\n", 3) 181 // 182 // output in the form of a Go quoted string literal: 183 // 184 // "abc3%%e x y z\n" 185 func FlatFormatter(w io.Writer) Formatter { 186 return (*flatFormatter)(IndentFormatter(w, "").(*indentFormatter)) 187 } 188 189 // Format implements Format interface. 190 func (f *flatFormatter) Format(format string, args ...interface{}) (n int, errno error) { 191 return (*indentFormatter)(f).format(true, format, args...) 192 } 193 194 // OutputFormat output escape character with backslash. 195 func OutputFormat(s string) string { 196 var buf bytes.Buffer 197 for _, old := range s { 198 if newVal, ok := replace[old]; ok { 199 buf.WriteString(newVal) 200 continue 201 } 202 buf.WriteRune(old) 203 } 204 205 return buf.String() 206 } 207 208 // RestoreFlags mark the Restore format 209 type RestoreFlags uint64 210 211 // Mutually exclusive group of `RestoreFlags`: 212 // [RestoreStringSingleQuotes, RestoreStringDoubleQuotes] 213 // [RestoreKeyWordUppercase, RestoreKeyWordLowercase] 214 // [RestoreNameUppercase, RestoreNameLowercase] 215 // [RestoreNameDoubleQuotes, RestoreNameBackQuotes] 216 // The flag with the left position in each group has a higher priority. 217 const ( 218 RestoreStringSingleQuotes RestoreFlags = 1 << iota 219 RestoreStringDoubleQuotes 220 RestoreStringEscapeBackslash 221 222 RestoreKeyWordUppercase 223 RestoreKeyWordLowercase 224 225 RestoreNameUppercase 226 RestoreNameLowercase 227 RestoreNameDoubleQuotes 228 RestoreNameBackQuotes 229 230 RestoreSpacesAroundBinaryOperation 231 RestoreBracketAroundBinaryOperation 232 233 RestoreStringWithoutCharset 234 RestoreStringWithoutDefaultCharset 235 236 RestoreTiDBSpecialComment 237 SkipPlacementRuleForRestore 238 RestoreWithTTLEnableOff 239 RestoreWithoutSchemaName 240 RestoreWithoutTableName 241 RestoreForNonPrepPlanCache 242 ) 243 244 const ( 245 // DefaultRestoreFlags is the default value of RestoreFlags. 246 DefaultRestoreFlags = RestoreStringSingleQuotes | RestoreKeyWordUppercase | RestoreNameBackQuotes 247 ) 248 249 func (rf RestoreFlags) has(flag RestoreFlags) bool { 250 return rf&flag != 0 251 } 252 253 // HasWithoutSchemaNameFlag returns a boolean indicating when `rf` has `RestoreWithoutSchemaName` flag. 254 func (rf RestoreFlags) HasWithoutSchemaNameFlag() bool { 255 return rf.has(RestoreWithoutSchemaName) 256 } 257 258 // HasWithoutTableNameFlag returns a boolean indicating when `rf` has `RestoreWithoutTableName` flag. 259 func (rf RestoreFlags) HasWithoutTableNameFlag() bool { 260 return rf.has(RestoreWithoutTableName) 261 } 262 263 // HasStringSingleQuotesFlag returns a boolean indicating when `rf` has `RestoreStringSingleQuotes` flag. 264 func (rf RestoreFlags) HasStringSingleQuotesFlag() bool { 265 return rf.has(RestoreStringSingleQuotes) 266 } 267 268 // HasStringDoubleQuotesFlag returns a boolean indicating whether `rf` has `RestoreStringDoubleQuotes` flag. 269 func (rf RestoreFlags) HasStringDoubleQuotesFlag() bool { 270 return rf.has(RestoreStringDoubleQuotes) 271 } 272 273 // HasStringEscapeBackslashFlag returns a boolean indicating whether `rf` has `RestoreStringEscapeBackslash` flag. 274 func (rf RestoreFlags) HasStringEscapeBackslashFlag() bool { 275 return rf.has(RestoreStringEscapeBackslash) 276 } 277 278 // HasKeyWordUppercaseFlag returns a boolean indicating whether `rf` has `RestoreKeyWordUppercase` flag. 279 func (rf RestoreFlags) HasKeyWordUppercaseFlag() bool { 280 return rf.has(RestoreKeyWordUppercase) 281 } 282 283 // HasKeyWordLowercaseFlag returns a boolean indicating whether `rf` has `RestoreKeyWordLowercase` flag. 284 func (rf RestoreFlags) HasKeyWordLowercaseFlag() bool { 285 return rf.has(RestoreKeyWordLowercase) 286 } 287 288 // HasNameUppercaseFlag returns a boolean indicating whether `rf` has `RestoreNameUppercase` flag. 289 func (rf RestoreFlags) HasNameUppercaseFlag() bool { 290 return rf.has(RestoreNameUppercase) 291 } 292 293 // HasNameLowercaseFlag returns a boolean indicating whether `rf` has `RestoreNameLowercase` flag. 294 func (rf RestoreFlags) HasNameLowercaseFlag() bool { 295 return rf.has(RestoreNameLowercase) 296 } 297 298 // HasNameDoubleQuotesFlag returns a boolean indicating whether `rf` has `RestoreNameDoubleQuotes` flag. 299 func (rf RestoreFlags) HasNameDoubleQuotesFlag() bool { 300 return rf.has(RestoreNameDoubleQuotes) 301 } 302 303 // HasNameBackQuotesFlag returns a boolean indicating whether `rf` has `RestoreNameBackQuotes` flag. 304 func (rf RestoreFlags) HasNameBackQuotesFlag() bool { 305 return rf.has(RestoreNameBackQuotes) 306 } 307 308 // HasSpacesAroundBinaryOperationFlag returns a boolean indicating 309 // whether `rf` has `RestoreSpacesAroundBinaryOperation` flag. 310 func (rf RestoreFlags) HasSpacesAroundBinaryOperationFlag() bool { 311 return rf.has(RestoreSpacesAroundBinaryOperation) 312 } 313 314 // HasRestoreBracketAroundBinaryOperation returns a boolean indicating 315 // whether `rf` has `RestoreBracketAroundBinaryOperation` flag. 316 func (rf RestoreFlags) HasRestoreBracketAroundBinaryOperation() bool { 317 return rf.has(RestoreBracketAroundBinaryOperation) 318 } 319 320 // HasStringWithoutDefaultCharset returns a boolean indicating 321 // whether `rf` has `RestoreStringWithoutDefaultCharset` flag. 322 func (rf RestoreFlags) HasStringWithoutDefaultCharset() bool { 323 return rf.has(RestoreStringWithoutDefaultCharset) 324 } 325 326 // HasStringWithoutCharset returns a boolean indicating whether `rf` has `RestoreStringWithoutCharset` flag. 327 func (rf RestoreFlags) HasStringWithoutCharset() bool { 328 return rf.has(RestoreStringWithoutCharset) 329 } 330 331 // HasTiDBSpecialCommentFlag returns a boolean indicating whether `rf` has `RestoreTiDBSpecialComment` flag. 332 func (rf RestoreFlags) HasTiDBSpecialCommentFlag() bool { 333 return rf.has(RestoreTiDBSpecialComment) 334 } 335 336 // HasSkipPlacementRuleForRestoreFlag returns a boolean indicating whether `rf` has `SkipPlacementRuleForRestore` flag. 337 func (rf RestoreFlags) HasSkipPlacementRuleForRestoreFlag() bool { 338 return rf.has(SkipPlacementRuleForRestore) 339 } 340 341 // HasRestoreWithTTLEnableOff returns a boolean indicating 342 // whether to force set TTL_ENABLE='OFF' when restoring a TTL table 343 func (rf RestoreFlags) HasRestoreWithTTLEnableOff() bool { 344 return rf.has(RestoreWithTTLEnableOff) 345 } 346 347 // HasRestoreForNonPrepPlanCache returns a boolean indicating whether `rf` has `RestoreForNonPrepPlanCache` flag. 348 func (rf RestoreFlags) HasRestoreForNonPrepPlanCache() bool { 349 return rf.has(RestoreForNonPrepPlanCache) 350 } 351 352 // RestoreWriter is the interface for `Restore` to write. 353 type RestoreWriter interface { 354 io.Writer 355 io.StringWriter 356 } 357 358 // RestoreCtx is `Restore` context to hold flags and writer. 359 type RestoreCtx struct { 360 Flags RestoreFlags 361 In RestoreWriter 362 DefaultDB string 363 CTERestorer 364 } 365 366 // NewRestoreCtx returns a new `RestoreCtx`. 367 func NewRestoreCtx(flags RestoreFlags, in RestoreWriter) *RestoreCtx { 368 return &RestoreCtx{Flags: flags, In: in, DefaultDB: ""} 369 } 370 371 // WriteKeyWord writes the `keyWord` into writer. 372 // `keyWord` will be converted format(uppercase and lowercase for now) according to `RestoreFlags`. 373 func (ctx *RestoreCtx) WriteKeyWord(keyWord string) { 374 switch { 375 case ctx.Flags.HasKeyWordUppercaseFlag(): 376 keyWord = strings.ToUpper(keyWord) 377 case ctx.Flags.HasKeyWordLowercaseFlag(): 378 keyWord = strings.ToLower(keyWord) 379 } 380 ctx.In.WriteString(keyWord) 381 } 382 383 // WriteWithSpecialComments writes a string with a special comment wrapped. 384 func (ctx *RestoreCtx) WriteWithSpecialComments(featureID string, fn func() error) error { 385 if !ctx.Flags.HasTiDBSpecialCommentFlag() { 386 return fn() 387 } 388 ctx.WritePlain("/*T!") 389 if len(featureID) != 0 { 390 ctx.WritePlainf("[%s]", featureID) 391 } 392 ctx.WritePlain(" ") 393 if err := fn(); err != nil { 394 return err 395 } 396 ctx.WritePlain(" */") 397 return nil 398 } 399 400 // WriteString writes the string into writer 401 // `str` may be wrapped in quotes and escaped according to RestoreFlags. 402 func (ctx *RestoreCtx) WriteString(str string) { 403 if ctx.Flags.HasStringEscapeBackslashFlag() { 404 str = strings.ReplaceAll(str, `\`, `\\`) 405 } 406 quotes := "" 407 switch { 408 case ctx.Flags.HasStringSingleQuotesFlag(): 409 str = strings.ReplaceAll(str, `'`, `''`) 410 quotes = `'` 411 case ctx.Flags.HasStringDoubleQuotesFlag(): 412 str = strings.ReplaceAll(str, `"`, `""`) 413 quotes = `"` 414 } 415 ctx.In.WriteString(quotes) 416 ctx.In.WriteString(str) 417 ctx.In.WriteString(quotes) 418 } 419 420 // WriteName writes the name into writer 421 // `name` maybe wrapped in quotes and escaped according to RestoreFlags. 422 func (ctx *RestoreCtx) WriteName(name string) { 423 switch { 424 case ctx.Flags.HasNameUppercaseFlag(): 425 name = strings.ToUpper(name) 426 case ctx.Flags.HasNameLowercaseFlag(): 427 name = strings.ToLower(name) 428 } 429 quotes := "" 430 switch { 431 case ctx.Flags.HasNameDoubleQuotesFlag(): 432 name = strings.ReplaceAll(name, `"`, `""`) 433 quotes = `"` 434 case ctx.Flags.HasNameBackQuotesFlag(): 435 name = strings.ReplaceAll(name, "`", "``") 436 quotes = "`" 437 } 438 439 // use `WriteString` directly instead of `fmt.Fprint` to get a better performance. 440 ctx.In.WriteString(quotes) 441 ctx.In.WriteString(name) 442 ctx.In.WriteString(quotes) 443 } 444 445 // WritePlain writes the plain text into writer without any handling. 446 func (ctx *RestoreCtx) WritePlain(plainText string) { 447 ctx.In.WriteString(plainText) 448 } 449 450 // WritePlainf write the plain text into writer without any handling. 451 func (ctx *RestoreCtx) WritePlainf(format string, a ...interface{}) { 452 fmt.Fprintf(ctx.In, format, a...) 453 } 454 455 // CTERestorer is used by WithClause related nodes restore. 456 type CTERestorer struct { 457 CTENames []string 458 } 459 460 // IsCTETableName returns true if the given tableName comes from CTE. 461 func (c *CTERestorer) IsCTETableName(nameL string) bool { 462 for _, n := range c.CTENames { 463 if n == nameL { 464 return true 465 } 466 } 467 return false 468 } 469 470 // RecordCTEName records the CTE name. 471 func (c *CTERestorer) RecordCTEName(nameL string) { 472 c.CTENames = append(c.CTENames, nameL) 473 } 474 475 // RestoreCTEFunc is used to restore CTE. 476 func (c *CTERestorer) RestoreCTEFunc() func() { 477 l := len(c.CTENames) 478 return func() { 479 if l == 0 { 480 c.CTENames = nil 481 } else { 482 c.CTENames = c.CTENames[:l] 483 } 484 } 485 }