github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/pretty.go (about) 1 // Copyright 2018 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 package tree 12 13 import ( 14 "bytes" 15 "fmt" 16 "strconv" 17 "strings" 18 19 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/sem/tree/treecmp" 20 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/sem/tree/treewindow" 21 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/types" 22 "github.com/cockroachdb/cockroachdb-parser/pkg/util/json" 23 "github.com/cockroachdb/cockroachdb-parser/pkg/util/pretty" 24 "github.com/cockroachdb/errors" 25 ) 26 27 // This file contains methods that convert statements to pretty Docs (a tree 28 // structure that can be pretty printed at a specific line width). Nodes 29 // implement the docer interface to allow this conversion. In general, 30 // a node implements doc by copying its Format method and returning a Doc 31 // structure instead of writing to a buffer. Some guidelines are below. 32 // 33 // Nodes should not precede themselves with a space. Instead, the parent 34 // structure should correctly add spaces when needed. 35 // 36 // nestName should be used for most `KEYWORD <expr>` constructs. 37 // 38 // Nodes that never need to line break or for which the Format method already 39 // produces a compact representation should not implement doc, but instead 40 // rely on the default fallback that uses .Format. Examples include datums 41 // and constants. 42 43 // PrettyCfg holds configuration for pretty printing statements. 44 type PrettyCfg struct { 45 // LineWidth is the desired maximum line width. 46 LineWidth int 47 // TabWidth is the amount of spaces to use for tabs when UseTabs is 48 // false. 49 TabWidth int 50 // DoNotNewLineAfterColName is true if we do not new line after table column names. 51 DoNotNewLineAfterColName bool 52 // Align, when set to another value than PrettyNoAlign, uses 53 // alignment for some constructs as a first choice. If not set or if 54 // the line width is insufficient, nesting is used instead. 55 Align PrettyAlignMode 56 // UseTabs indicates whether to use tab chars to signal indentation. 57 UseTabs bool 58 // Simplify, when set, removes extraneous parentheses. 59 Simplify bool 60 // Case, if set, transforms case-insensitive strings (like SQL keywords). 61 Case func(string) string 62 // JSONFmt, when set, pretty-prints strings that are asserted or cast 63 // to JSON. 64 JSONFmt bool 65 // ValueRedaction, when set, surrounds literal values with redaction markers. 66 ValueRedaction bool 67 } 68 69 // DefaultPrettyCfg returns a PrettyCfg with the default 70 // configuration. 71 func DefaultPrettyCfg() PrettyCfg { 72 return PrettyCfg{ 73 LineWidth: DefaultLineWidth, 74 Simplify: true, 75 TabWidth: 4, 76 UseTabs: true, 77 Align: PrettyNoAlign, // TODO(knz): I really want this to be AlignAndDeindent 78 } 79 } 80 81 // PrettyAlignMode directs which alignment mode to use. 82 // 83 // TODO(knz/mjibson): this variety of options currently exists so as 84 // to enable comparisons and gauging individual preferences. We should 85 // aim to remove some or all of these options in the future. 86 type PrettyAlignMode int 87 88 const ( 89 // PrettyNoAlign disables alignment. 90 PrettyNoAlign PrettyAlignMode = 0 91 // PrettyAlignOnly aligns sub-clauses only and preserves the 92 // hierarchy of logical operators. 93 PrettyAlignOnly = 1 94 // PrettyAlignAndDeindent does the work of PrettyAlignOnly and also 95 // de-indents AND and OR operators. 96 PrettyAlignAndDeindent = 2 97 // PrettyAlignAndExtraIndent does the work of PrettyAlignOnly and 98 // also extra indents the operands of AND and OR operators so 99 // that they appear aligned but also indented. 100 PrettyAlignAndExtraIndent = 3 101 ) 102 103 // CaseMode directs which casing mode to use. 104 type CaseMode int 105 106 const ( 107 // LowerCase transforms case-insensitive strings (like SQL keywords) to lowercase. 108 LowerCase CaseMode = 0 109 // UpperCase transforms case-insensitive strings (like SQL keywords) to uppercase. 110 UpperCase CaseMode = 1 111 ) 112 113 // LineWidthMode directs which mode of line width to use. 114 type LineWidthMode int 115 116 const ( 117 // DefaultLineWidth is the line width used with the default pretty-printing configuration. 118 DefaultLineWidth = 60 119 // ConsoleLineWidth is the line width used on the frontend console. 120 ConsoleLineWidth = 108 121 ) 122 123 // keywordWithText returns a pretty.Keyword with left and/or right 124 // sides concat'd as a pretty.Text. 125 func (p *PrettyCfg) keywordWithText(left, keyword, right string) pretty.Doc { 126 doc := pretty.Keyword(keyword) 127 if left != "" { 128 doc = pretty.Concat(pretty.Text(left), doc) 129 } 130 if right != "" { 131 doc = pretty.Concat(doc, pretty.Text(right)) 132 } 133 return doc 134 } 135 136 func (p *PrettyCfg) bracket(l string, d pretty.Doc, r string) pretty.Doc { 137 return p.bracketDoc(pretty.Text(l), d, pretty.Text(r)) 138 } 139 140 func (p *PrettyCfg) bracketDoc(l, d, r pretty.Doc) pretty.Doc { 141 return pretty.BracketDoc(l, d, r) 142 } 143 144 func (p *PrettyCfg) bracketKeyword( 145 leftKeyword, leftParen string, inner pretty.Doc, rightParen, rightKeyword string, 146 ) pretty.Doc { 147 var left, right pretty.Doc 148 if leftKeyword != "" { 149 left = p.keywordWithText("", leftKeyword, leftParen) 150 } else { 151 left = pretty.Text(leftParen) 152 } 153 if rightKeyword != "" { 154 right = p.keywordWithText(rightParen, rightKeyword, "") 155 } else { 156 right = pretty.Text(rightParen) 157 } 158 return p.bracketDoc(left, inner, right) 159 } 160 161 // Pretty pretty prints stmt with default options. 162 func Pretty(stmt NodeFormatter) (string, error) { 163 cfg := DefaultPrettyCfg() 164 return cfg.Pretty(stmt) 165 } 166 167 // Pretty pretty prints stmt with specified options. 168 func (p *PrettyCfg) Pretty(stmt NodeFormatter) (string, error) { 169 doc := p.Doc(stmt) 170 return pretty.Pretty(doc, p.LineWidth, p.UseTabs, p.TabWidth, p.Case) 171 } 172 173 // Doc converts f (generally a Statement) to a pretty.Doc. If f does not have a 174 // native conversion, its .Format representation is used as a simple Text Doc. 175 func (p *PrettyCfg) Doc(f NodeFormatter) pretty.Doc { 176 if f, ok := f.(docer); ok { 177 doc := f.doc(p) 178 return doc 179 } 180 return p.docAsString(f) 181 } 182 183 func (p *PrettyCfg) docAsString(f NodeFormatter) pretty.Doc { 184 txt := AsStringWithFlags(f, p.fmtFlags()) 185 return pretty.Text(strings.TrimSpace(txt)) 186 } 187 188 func (p *PrettyCfg) fmtFlags() FmtFlags { 189 prettyFlags := FmtShowPasswords | FmtParsable | FmtTagDollarQuotes 190 if p.ValueRedaction { 191 prettyFlags |= FmtMarkRedactionNode | FmtOmitNameRedaction 192 } 193 return prettyFlags 194 } 195 196 func (p *PrettyCfg) nestUnder(a, b pretty.Doc) pretty.Doc { 197 if p.Align != PrettyNoAlign { 198 return pretty.AlignUnder(a, b) 199 } 200 return pretty.NestUnder(a, b) 201 } 202 203 // rlTable produces a Table using Right alignment of the first column. 204 func (p *PrettyCfg) rlTable(rows ...pretty.TableRow) pretty.Doc { 205 alignment := pretty.TableNoAlign 206 if p.Align != PrettyNoAlign { 207 alignment = pretty.TableRightAlignFirstColumn 208 } 209 return pretty.Table(alignment, pretty.Keyword, p.DoNotNewLineAfterColName, rows...) 210 } 211 212 // llTable produces a Table using Left alignment of the first column. 213 func (p *PrettyCfg) llTable(docFn func(string) pretty.Doc, rows ...pretty.TableRow) pretty.Doc { 214 alignment := pretty.TableNoAlign 215 if p.Align != PrettyNoAlign { 216 alignment = pretty.TableLeftAlignFirstColumn 217 } 218 return pretty.Table(alignment, docFn, p.DoNotNewLineAfterColName, rows...) 219 } 220 221 func (p *PrettyCfg) row(lbl string, d pretty.Doc) pretty.TableRow { 222 return pretty.TableRow{Label: lbl, Doc: d} 223 } 224 225 var emptyRow = pretty.TableRow{} 226 227 func (p *PrettyCfg) unrow(r pretty.TableRow) pretty.Doc { 228 if r.Doc == nil { 229 return pretty.Nil 230 } 231 if r.Label == "" { 232 return r.Doc 233 } 234 return p.nestUnder(pretty.Text(r.Label), r.Doc) 235 } 236 237 func (p *PrettyCfg) commaSeparated(d ...pretty.Doc) pretty.Doc { 238 return pretty.Join(",", d...) 239 } 240 241 func (p *PrettyCfg) joinNestedOuter(lbl string, d ...pretty.Doc) pretty.Doc { 242 if len(d) == 0 { 243 return pretty.Nil 244 } 245 switch p.Align { 246 case PrettyAlignAndDeindent: 247 return pretty.JoinNestedOuter(lbl, pretty.Keyword, d...) 248 case PrettyAlignAndExtraIndent: 249 items := make([]pretty.TableRow, len(d)) 250 for i, dd := range d { 251 if i > 0 { 252 items[i].Label = lbl 253 } 254 items[i].Doc = dd 255 } 256 return pretty.Table(pretty.TableRightAlignFirstColumn, pretty.Keyword, p.DoNotNewLineAfterColName, items...) 257 default: 258 return pretty.JoinNestedRight(pretty.Keyword(lbl), d...) 259 } 260 } 261 262 // docer is implemented by nodes that can convert themselves into 263 // pretty.Docs. If nodes cannot, node.Format is used instead as a Text Doc. 264 type docer interface { 265 doc(*PrettyCfg) pretty.Doc 266 } 267 268 // tableDocer is implemented by nodes that can convert themselves 269 // into []pretty.TableRow, i.e. a table. 270 type tableDocer interface { 271 docTable(*PrettyCfg) []pretty.TableRow 272 } 273 274 func (node SelectExprs) doc(p *PrettyCfg) pretty.Doc { 275 d := make([]pretty.Doc, len(node)) 276 for i, e := range node { 277 d[i] = e.doc(p) 278 } 279 return p.commaSeparated(d...) 280 } 281 282 func (node SelectExpr) doc(p *PrettyCfg) pretty.Doc { 283 e := node.Expr 284 if p.Simplify { 285 e = StripParens(e) 286 } 287 d := p.Doc(e) 288 if node.As != "" { 289 d = p.nestUnder( 290 d, 291 pretty.Concat(p.keywordWithText("", "AS", " "), p.Doc(&node.As)), 292 ) 293 } 294 return d 295 } 296 297 func (node TableExprs) doc(p *PrettyCfg) pretty.Doc { 298 if len(node) == 0 { 299 return pretty.Nil 300 } 301 d := make([]pretty.Doc, len(node)) 302 for i, e := range node { 303 if p.Simplify { 304 e = StripTableParens(e) 305 } 306 d[i] = p.Doc(e) 307 } 308 return p.commaSeparated(d...) 309 } 310 311 func (node *Where) doc(p *PrettyCfg) pretty.Doc { 312 return p.unrow(node.docRow(p)) 313 } 314 315 func (node *Where) docRow(p *PrettyCfg) pretty.TableRow { 316 if node == nil { 317 return emptyRow 318 } 319 e := node.Expr 320 if p.Simplify { 321 e = StripParens(e) 322 } 323 return p.row(node.Type, p.Doc(e)) 324 } 325 326 func (node *GroupBy) doc(p *PrettyCfg) pretty.Doc { 327 return p.unrow(node.docRow(p)) 328 } 329 330 func (node *GroupBy) docRow(p *PrettyCfg) pretty.TableRow { 331 if len(*node) == 0 { 332 return emptyRow 333 } 334 d := make([]pretty.Doc, len(*node)) 335 for i, e := range *node { 336 // Beware! The GROUP BY items should never be simplified by 337 // stripping parentheses, because parentheses there are 338 // semantically important. 339 d[i] = p.Doc(e) 340 } 341 return p.row("GROUP BY", p.commaSeparated(d...)) 342 } 343 344 // flattenOp populates a slice with all the leaves operands of an expression 345 // tree where all the nodes satisfy the given predicate. 346 func (p *PrettyCfg) flattenOp( 347 e Expr, 348 pred func(e Expr, recurse func(e Expr)) bool, 349 formatOperand func(e Expr) pretty.Doc, 350 in []pretty.Doc, 351 ) []pretty.Doc { 352 if ok := pred(e, func(sub Expr) { 353 in = p.flattenOp(sub, pred, formatOperand, in) 354 }); ok { 355 return in 356 } 357 return append(in, formatOperand(e)) 358 } 359 360 func (p *PrettyCfg) peelAndOrOperand(e Expr) Expr { 361 if !p.Simplify { 362 return e 363 } 364 stripped := StripParens(e) 365 switch stripped.(type) { 366 case *BinaryExpr, *ComparisonExpr, *RangeCond, *FuncExpr, *IndirectionExpr, 367 *UnaryExpr, *AnnotateTypeExpr, *CastExpr, *ColumnItem, *UnresolvedName: 368 // All these expressions have higher precedence than binary 369 // expressions. 370 return stripped 371 } 372 // Everything else - we don't know. Be conservative and keep the 373 // original form. 374 return e 375 } 376 377 func (node *AndExpr) doc(p *PrettyCfg) pretty.Doc { 378 pred := func(e Expr, recurse func(e Expr)) bool { 379 if a, ok := e.(*AndExpr); ok { 380 recurse(a.Left) 381 recurse(a.Right) 382 return true 383 } 384 return false 385 } 386 formatOperand := func(e Expr) pretty.Doc { 387 return p.Doc(p.peelAndOrOperand(e)) 388 } 389 operands := p.flattenOp(node.Left, pred, formatOperand, nil) 390 operands = p.flattenOp(node.Right, pred, formatOperand, operands) 391 return p.joinNestedOuter("AND", operands...) 392 } 393 394 func (node *OrExpr) doc(p *PrettyCfg) pretty.Doc { 395 pred := func(e Expr, recurse func(e Expr)) bool { 396 if a, ok := e.(*OrExpr); ok { 397 recurse(a.Left) 398 recurse(a.Right) 399 return true 400 } 401 return false 402 } 403 formatOperand := func(e Expr) pretty.Doc { 404 return p.Doc(p.peelAndOrOperand(e)) 405 } 406 operands := p.flattenOp(node.Left, pred, formatOperand, nil) 407 operands = p.flattenOp(node.Right, pred, formatOperand, operands) 408 return p.joinNestedOuter("OR", operands...) 409 } 410 411 func (node *Exprs) doc(p *PrettyCfg) pretty.Doc { 412 if node == nil || len(*node) == 0 { 413 return pretty.Nil 414 } 415 d := make([]pretty.Doc, len(*node)) 416 for i, e := range *node { 417 if p.Simplify { 418 e = StripParens(e) 419 } 420 d[i] = p.Doc(e) 421 } 422 return p.commaSeparated(d...) 423 } 424 425 // peelBinaryOperand conditionally (p.Simplify) removes the 426 // parentheses around an expression. The parentheses are always 427 // removed in the following conditions: 428 // - if the operand is a unary operator (these are always 429 // of higher precedence): "(-a) * b" -> "-a * b" 430 // - if the operand is a binary operator and its precedence 431 // is guaranteed to be higher: "(a * b) + c" -> "a * b + c" 432 // 433 // Additionally, iff sameLevel is set, then parentheses are removed 434 // around any binary operator that has the same precedence level as 435 // the parent. 436 // sameLevel can be set: 437 // 438 // - for the left operand of all binary expressions, because 439 // (in pg SQL) all binary expressions are left-associative. 440 // This rewrites e.g. "(a + b) - c" -> "a + b - c" 441 // and "(a - b) + c" -> "a - b + c" 442 // - for the right operand when the parent operator is known 443 // to be fully associative, e.g. 444 // "a + (b - c)" -> "a + b - c" because "+" is fully assoc, 445 // but "a - (b + c)" cannot be simplified because "-" is not fully associative. 446 func (p *PrettyCfg) peelBinaryOperand(e Expr, sameLevel bool, parenPrio int) Expr { 447 if !p.Simplify { 448 return e 449 } 450 stripped := StripParens(e) 451 switch te := stripped.(type) { 452 case *BinaryExpr: 453 // Do not fold explicit operators. 454 if te.Operator.IsExplicitOperator { 455 return e 456 } 457 childPrio := binaryOpPrio[te.Operator.Symbol] 458 if childPrio < parenPrio || (sameLevel && childPrio == parenPrio) { 459 return stripped 460 } 461 case *FuncExpr, *UnaryExpr, *AnnotateTypeExpr, *IndirectionExpr, 462 *CastExpr, *ColumnItem, *UnresolvedName: 463 // All these expressions have higher precedence than binary expressions. 464 return stripped 465 } 466 // Everything else - we don't know. Be conservative and keep the 467 // original form. 468 return e 469 } 470 471 func (node *BinaryExpr) doc(p *PrettyCfg) pretty.Doc { 472 // All the binary operators are at least left-associative. 473 // So we can always simplify "(a OP b) OP c" to "a OP b OP c". 474 parenPrio := binaryOpPrio[node.Operator.Symbol] 475 leftOperand := p.peelBinaryOperand(node.Left, true /*sameLevel*/, parenPrio) 476 // If the binary operator is also fully associative, 477 // we can also simplify "a OP (b OP c)" to "a OP b OP c". 478 opFullyAssoc := binaryOpFullyAssoc[node.Operator.Symbol] 479 rightOperand := p.peelBinaryOperand(node.Right, opFullyAssoc, parenPrio) 480 481 opDoc := pretty.Text(node.Operator.String()) 482 var res pretty.Doc 483 if !node.Operator.Symbol.IsPadded() { 484 res = pretty.JoinDoc(opDoc, p.Doc(leftOperand), p.Doc(rightOperand)) 485 } else { 486 pred := func(e Expr, recurse func(e Expr)) bool { 487 if b, ok := e.(*BinaryExpr); ok && b.Operator == node.Operator { 488 leftSubOperand := p.peelBinaryOperand(b.Left, true /*sameLevel*/, parenPrio) 489 rightSubOperand := p.peelBinaryOperand(b.Right, opFullyAssoc, parenPrio) 490 recurse(leftSubOperand) 491 recurse(rightSubOperand) 492 return true 493 } 494 return false 495 } 496 formatOperand := func(e Expr) pretty.Doc { 497 return p.Doc(e) 498 } 499 operands := p.flattenOp(leftOperand, pred, formatOperand, nil) 500 operands = p.flattenOp(rightOperand, pred, formatOperand, operands) 501 res = pretty.JoinNestedRight( 502 opDoc, operands...) 503 } 504 return pretty.Group(res) 505 } 506 507 func (node *ParenExpr) doc(p *PrettyCfg) pretty.Doc { 508 return p.bracket("(", p.Doc(node.Expr), ")") 509 } 510 511 func (node *ParenSelect) doc(p *PrettyCfg) pretty.Doc { 512 return p.bracket("(", p.Doc(node.Select), ")") 513 } 514 515 func (node *ParenTableExpr) doc(p *PrettyCfg) pretty.Doc { 516 return p.bracket("(", p.Doc(node.Expr), ")") 517 } 518 519 func (node *Limit) doc(p *PrettyCfg) pretty.Doc { 520 res := pretty.Nil 521 for i, r := range node.docTable(p) { 522 if r.Doc != nil { 523 if i > 0 { 524 res = pretty.Concat(res, pretty.Line) 525 } 526 res = pretty.Concat(res, p.nestUnder(pretty.Text(r.Label), r.Doc)) 527 } 528 } 529 return res 530 } 531 532 func (node *Limit) docTable(p *PrettyCfg) []pretty.TableRow { 533 if node == nil { 534 return nil 535 } 536 res := make([]pretty.TableRow, 0, 2) 537 if node.Count != nil { 538 e := node.Count 539 if p.Simplify { 540 e = StripParens(e) 541 } 542 res = append(res, p.row("LIMIT", p.Doc(e))) 543 } else if node.LimitAll { 544 res = append(res, p.row("LIMIT", pretty.Keyword("ALL"))) 545 } 546 if node.Offset != nil { 547 e := node.Offset 548 if p.Simplify { 549 e = StripParens(e) 550 } 551 res = append(res, p.row("OFFSET", p.Doc(e))) 552 } 553 return res 554 } 555 556 func (node *OrderBy) doc(p *PrettyCfg) pretty.Doc { 557 return p.unrow(node.docRow(p)) 558 } 559 560 func (node *OrderBy) docRow(p *PrettyCfg) pretty.TableRow { 561 if node == nil || len(*node) == 0 { 562 return emptyRow 563 } 564 d := make([]pretty.Doc, len(*node)) 565 for i, e := range *node { 566 // Beware! The ORDER BY items should never be simplified, 567 // because parentheses there are semantically important. 568 d[i] = p.Doc(e) 569 } 570 return p.row("ORDER BY", p.commaSeparated(d...)) 571 } 572 573 func (node *Select) doc(p *PrettyCfg) pretty.Doc { 574 return p.rlTable(node.docTable(p)...) 575 } 576 577 func (node *Select) docTable(p *PrettyCfg) []pretty.TableRow { 578 items := make([]pretty.TableRow, 0, 9) 579 items = append(items, node.With.docRow(p)) 580 if s, ok := node.Select.(tableDocer); ok { 581 items = append(items, s.docTable(p)...) 582 } else { 583 items = append(items, p.row("", p.Doc(node.Select))) 584 } 585 items = append(items, node.OrderBy.docRow(p)) 586 items = append(items, node.Limit.docTable(p)...) 587 items = append(items, node.Locking.docTable(p)...) 588 return items 589 } 590 591 func (node *SelectClause) doc(p *PrettyCfg) pretty.Doc { 592 return p.rlTable(node.docTable(p)...) 593 } 594 595 func (node *SelectClause) docTable(p *PrettyCfg) []pretty.TableRow { 596 if node.TableSelect { 597 return []pretty.TableRow{p.row("TABLE", p.Doc(node.From.Tables[0]))} 598 } 599 exprs := node.Exprs.doc(p) 600 if node.Distinct { 601 if node.DistinctOn != nil { 602 exprs = pretty.ConcatLine(p.Doc(&node.DistinctOn), exprs) 603 } else { 604 exprs = pretty.ConcatLine(pretty.Keyword("DISTINCT"), exprs) 605 } 606 } 607 return []pretty.TableRow{ 608 p.row("SELECT", exprs), 609 node.From.docRow(p), 610 node.Where.docRow(p), 611 node.GroupBy.docRow(p), 612 node.Having.docRow(p), 613 node.Window.docRow(p), 614 } 615 } 616 617 func (node *From) doc(p *PrettyCfg) pretty.Doc { 618 return p.unrow(node.docRow(p)) 619 } 620 621 func (node *From) docRow(p *PrettyCfg) pretty.TableRow { 622 if node == nil || len(node.Tables) == 0 { 623 return emptyRow 624 } 625 d := node.Tables.doc(p) 626 if node.AsOf.Expr != nil { 627 d = p.nestUnder( 628 d, 629 p.Doc(&node.AsOf), 630 ) 631 } 632 return p.row("FROM", d) 633 } 634 635 func (node *Window) doc(p *PrettyCfg) pretty.Doc { 636 return p.unrow(node.docRow(p)) 637 } 638 639 func (node *Window) docRow(p *PrettyCfg) pretty.TableRow { 640 if node == nil || len(*node) == 0 { 641 return emptyRow 642 } 643 d := make([]pretty.Doc, len(*node)) 644 for i, e := range *node { 645 d[i] = pretty.Fold(pretty.Concat, 646 pretty.Text(e.Name.String()), 647 p.keywordWithText(" ", "AS", " "), 648 p.Doc(e), 649 ) 650 } 651 return p.row("WINDOW", p.commaSeparated(d...)) 652 } 653 654 func (node *With) doc(p *PrettyCfg) pretty.Doc { 655 return p.unrow(node.docRow(p)) 656 } 657 658 func (node *With) docRow(p *PrettyCfg) pretty.TableRow { 659 if node == nil { 660 return emptyRow 661 } 662 d := make([]pretty.Doc, len(node.CTEList)) 663 for i, cte := range node.CTEList { 664 asString := "AS" 665 switch cte.Mtr { 666 case CTEMaterializeAlways: 667 asString += " MATERIALIZED" 668 case CTEMaterializeNever: 669 asString += " NOT MATERIALIZED" 670 } 671 d[i] = p.nestUnder( 672 p.Doc(&cte.Name), 673 p.bracketKeyword(asString, " (", p.Doc(cte.Stmt), ")", ""), 674 ) 675 } 676 kw := "WITH" 677 if node.Recursive { 678 kw = "WITH RECURSIVE" 679 } 680 return p.row(kw, p.commaSeparated(d...)) 681 } 682 683 func (node *Subquery) doc(p *PrettyCfg) pretty.Doc { 684 d := pretty.Text("<unknown>") 685 if node.Select != nil { 686 d = p.Doc(node.Select) 687 } 688 if node.Exists { 689 d = pretty.Concat( 690 pretty.Keyword("EXISTS"), 691 d, 692 ) 693 } 694 return d 695 } 696 697 func (node *AliasedTableExpr) doc(p *PrettyCfg) pretty.Doc { 698 d := p.Doc(node.Expr) 699 if node.Lateral { 700 d = pretty.Concat( 701 p.keywordWithText("", "LATERAL", " "), 702 d, 703 ) 704 } 705 if node.IndexFlags != nil { 706 d = pretty.Concat( 707 d, 708 p.Doc(node.IndexFlags), 709 ) 710 } 711 if node.Ordinality { 712 d = pretty.Concat( 713 d, 714 p.keywordWithText(" ", "WITH ORDINALITY", ""), 715 ) 716 } 717 if node.As.Alias != "" { 718 d = p.nestUnder( 719 d, 720 pretty.Concat( 721 p.keywordWithText("", "AS", " "), 722 p.Doc(&node.As), 723 ), 724 ) 725 } 726 return d 727 } 728 729 func (node *FuncExpr) doc(p *PrettyCfg) pretty.Doc { 730 d := p.Doc(&node.Func) 731 732 if len(node.Exprs) > 0 { 733 args := node.Exprs.doc(p) 734 if node.Type != 0 { 735 args = pretty.ConcatLine( 736 pretty.Text(funcTypeName[node.Type]), 737 args, 738 ) 739 } 740 741 if node.AggType == GeneralAgg && len(node.OrderBy) > 0 { 742 args = pretty.ConcatSpace(args, node.OrderBy.doc(p)) 743 } 744 d = pretty.Concat(d, p.bracket("(", args, ")")) 745 } else { 746 d = pretty.Concat(d, pretty.Text("()")) 747 } 748 if node.AggType == OrderedSetAgg && len(node.OrderBy) > 0 { 749 args := node.OrderBy.doc(p) 750 d = pretty.Concat(d, p.bracket("WITHIN GROUP (", args, ")")) 751 } 752 if node.Filter != nil { 753 d = pretty.Fold(pretty.ConcatSpace, 754 d, 755 pretty.Keyword("FILTER"), 756 p.bracket("(", 757 p.nestUnder(pretty.Keyword("WHERE"), p.Doc(node.Filter)), 758 ")")) 759 } 760 if window := node.WindowDef; window != nil { 761 var over pretty.Doc 762 if window.Name != "" { 763 over = p.Doc(&window.Name) 764 } else { 765 over = p.Doc(window) 766 } 767 d = pretty.Fold(pretty.ConcatSpace, 768 d, 769 pretty.Keyword("OVER"), 770 over, 771 ) 772 } 773 return d 774 } 775 776 func (node *WindowDef) doc(p *PrettyCfg) pretty.Doc { 777 rows := make([]pretty.TableRow, 0, 4) 778 if node.RefName != "" { 779 rows = append(rows, p.row("", p.Doc(&node.RefName))) 780 } 781 if len(node.Partitions) > 0 { 782 rows = append(rows, p.row("PARTITION BY", p.Doc(&node.Partitions))) 783 } 784 if len(node.OrderBy) > 0 { 785 rows = append(rows, node.OrderBy.docRow(p)) 786 } 787 if node.Frame != nil { 788 rows = append(rows, node.Frame.docRow(p)) 789 } 790 if len(rows) == 0 { 791 return pretty.Text("()") 792 } 793 return p.bracket("(", p.rlTable(rows...), ")") 794 } 795 796 func (wf *WindowFrame) docRow(p *PrettyCfg) pretty.TableRow { 797 kw := "RANGE" 798 if wf.Mode == treewindow.ROWS { 799 kw = "ROWS" 800 } else if wf.Mode == treewindow.GROUPS { 801 kw = "GROUPS" 802 } 803 d := p.Doc(wf.Bounds.StartBound) 804 if wf.Bounds.EndBound != nil { 805 d = p.rlTable( 806 p.row("BETWEEN", d), 807 p.row("AND", p.Doc(wf.Bounds.EndBound)), 808 ) 809 } 810 if wf.Exclusion != treewindow.NoExclusion { 811 d = pretty.Stack(d, pretty.Keyword(wf.Exclusion.String())) 812 } 813 return p.row(kw, d) 814 } 815 816 func (node *WindowFrameBound) doc(p *PrettyCfg) pretty.Doc { 817 switch node.BoundType { 818 case treewindow.UnboundedPreceding: 819 return pretty.Keyword("UNBOUNDED PRECEDING") 820 case treewindow.OffsetPreceding: 821 return pretty.ConcatSpace(p.Doc(node.OffsetExpr), pretty.Keyword("PRECEDING")) 822 case treewindow.CurrentRow: 823 return pretty.Keyword("CURRENT ROW") 824 case treewindow.OffsetFollowing: 825 return pretty.ConcatSpace(p.Doc(node.OffsetExpr), pretty.Keyword("FOLLOWING")) 826 case treewindow.UnboundedFollowing: 827 return pretty.Keyword("UNBOUNDED FOLLOWING") 828 default: 829 panic(errors.AssertionFailedf("unexpected type %d", errors.Safe(node.BoundType))) 830 } 831 } 832 833 func (node *LockingClause) doc(p *PrettyCfg) pretty.Doc { 834 return p.rlTable(node.docTable(p)...) 835 } 836 837 func (node *LockingClause) docTable(p *PrettyCfg) []pretty.TableRow { 838 items := make([]pretty.TableRow, len(*node)) 839 for i, n := range *node { 840 items[i] = p.row("", p.Doc(n)) 841 } 842 return items 843 } 844 845 func (node *LockingItem) doc(p *PrettyCfg) pretty.Doc { 846 return p.rlTable(node.docTable(p)...) 847 } 848 849 func (node *LockingItem) docTable(p *PrettyCfg) []pretty.TableRow { 850 if node.Strength == ForNone { 851 return nil 852 } 853 items := make([]pretty.TableRow, 0, 3) 854 items = append(items, node.Strength.docTable(p)...) 855 if len(node.Targets) > 0 { 856 items = append(items, p.row("OF", p.Doc(&node.Targets))) 857 } 858 items = append(items, node.WaitPolicy.docTable(p)...) 859 return items 860 } 861 862 func (node LockingStrength) doc(p *PrettyCfg) pretty.Doc { 863 return p.rlTable(node.docTable(p)...) 864 } 865 866 func (node LockingStrength) docTable(p *PrettyCfg) []pretty.TableRow { 867 str := node.String() 868 if str == "" { 869 return nil 870 } 871 return []pretty.TableRow{p.row("", pretty.Keyword(str))} 872 } 873 874 func (node LockingWaitPolicy) doc(p *PrettyCfg) pretty.Doc { 875 return p.rlTable(node.docTable(p)...) 876 } 877 878 func (node LockingWaitPolicy) docTable(p *PrettyCfg) []pretty.TableRow { 879 str := node.String() 880 if str == "" { 881 return nil 882 } 883 return []pretty.TableRow{p.row("", pretty.Keyword(str))} 884 } 885 886 func (p *PrettyCfg) peelCompOperand(e Expr) Expr { 887 if !p.Simplify { 888 return e 889 } 890 stripped := StripParens(e) 891 switch stripped.(type) { 892 case *FuncExpr, *IndirectionExpr, *UnaryExpr, 893 *AnnotateTypeExpr, *CastExpr, *ColumnItem, *UnresolvedName: 894 return stripped 895 } 896 return e 897 } 898 899 func (node *ComparisonExpr) doc(p *PrettyCfg) pretty.Doc { 900 opStr := node.Operator.String() 901 // IS and IS NOT are equivalent to IS NOT DISTINCT FROM and IS DISTINCT 902 // FROM, respectively, when the RHS is true or false. We prefer the less 903 // verbose IS and IS NOT in those cases. 904 if node.Operator.Symbol == treecmp.IsDistinctFrom && (node.Right == DBoolTrue || node.Right == DBoolFalse) { 905 opStr = "IS NOT" 906 } else if node.Operator.Symbol == treecmp.IsNotDistinctFrom && (node.Right == DBoolTrue || node.Right == DBoolFalse) { 907 opStr = "IS" 908 } 909 opDoc := pretty.Keyword(opStr) 910 if node.Operator.Symbol.HasSubOperator() { 911 opDoc = pretty.ConcatSpace(pretty.Text(node.SubOperator.String()), opDoc) 912 } 913 return pretty.Group( 914 pretty.JoinNestedRight( 915 opDoc, 916 p.Doc(p.peelCompOperand(node.Left)), 917 p.Doc(p.peelCompOperand(node.Right)))) 918 } 919 920 func (node *AliasClause) doc(p *PrettyCfg) pretty.Doc { 921 d := pretty.Text(node.Alias.String()) 922 if len(node.Cols) != 0 { 923 d = p.nestUnder(d, p.bracket("(", p.Doc(&node.Cols), ")")) 924 } 925 return d 926 } 927 928 func (node *JoinTableExpr) doc(p *PrettyCfg) pretty.Doc { 929 // buf will contain the fully populated sequence of join keywords. 930 var buf bytes.Buffer 931 cond := pretty.Nil 932 if _, isNatural := node.Cond.(NaturalJoinCond); isNatural { 933 // Natural joins have a different syntax: 934 // "<a> NATURAL <join_type> [<join_hint>] JOIN <b>" 935 buf.WriteString("NATURAL ") 936 } else { 937 // Regular joins: 938 // "<a> <join type> [<join hint>] JOIN <b>" 939 if node.Cond != nil { 940 cond = p.Doc(node.Cond) 941 } 942 } 943 944 if node.JoinType != "" { 945 buf.WriteString(node.JoinType) 946 buf.WriteByte(' ') 947 if node.Hint != "" { 948 buf.WriteString(node.Hint) 949 buf.WriteByte(' ') 950 } 951 } 952 buf.WriteString("JOIN") 953 954 return p.joinNestedOuter( 955 buf.String(), 956 p.Doc(node.Left), 957 pretty.ConcatSpace(p.Doc(node.Right), cond)) 958 } 959 960 func (node *OnJoinCond) doc(p *PrettyCfg) pretty.Doc { 961 e := node.Expr 962 if p.Simplify { 963 e = StripParens(e) 964 } 965 return p.nestUnder(pretty.Keyword("ON"), p.Doc(e)) 966 } 967 968 func (node *Insert) doc(p *PrettyCfg) pretty.Doc { 969 items := make([]pretty.TableRow, 0, 9) 970 items = append(items, node.With.docRow(p)) 971 kw := "INSERT" 972 if node.OnConflict.IsUpsertAlias() { 973 kw = "UPSERT" 974 } 975 items = append(items, p.row(kw, pretty.Nil)) 976 977 into := p.Doc(node.Table) 978 if node.Columns != nil { 979 into = p.nestUnder(into, p.bracket("(", p.Doc(&node.Columns), ")")) 980 } 981 items = append(items, p.row("INTO", into)) 982 983 if node.DefaultValues() { 984 items = append(items, p.row("", pretty.Keyword("DEFAULT VALUES"))) 985 } else { 986 items = append(items, node.Rows.docTable(p)...) 987 } 988 989 if node.OnConflict != nil && !node.OnConflict.IsUpsertAlias() { 990 cond := pretty.Nil 991 if len(node.OnConflict.Constraint) > 0 { 992 cond = p.nestUnder(pretty.Text("ON CONSTRAINT"), p.Doc(&node.OnConflict.Constraint)) 993 } 994 if len(node.OnConflict.Columns) > 0 { 995 cond = p.bracket("(", p.Doc(&node.OnConflict.Columns), ")") 996 } 997 items = append(items, p.row("ON CONFLICT", cond)) 998 if node.OnConflict.ArbiterPredicate != nil { 999 items = append(items, p.row("WHERE", p.Doc(node.OnConflict.ArbiterPredicate))) 1000 } 1001 1002 if node.OnConflict.DoNothing { 1003 items = append(items, p.row("DO", pretty.Keyword("NOTHING"))) 1004 } else { 1005 items = append(items, p.row("DO", 1006 p.nestUnder(pretty.Keyword("UPDATE SET"), p.Doc(&node.OnConflict.Exprs)))) 1007 if node.OnConflict.Where != nil { 1008 items = append(items, node.OnConflict.Where.docRow(p)) 1009 } 1010 } 1011 } 1012 1013 items = append(items, p.docReturning(node.Returning)) 1014 return p.rlTable(items...) 1015 } 1016 1017 func (node *NameList) doc(p *PrettyCfg) pretty.Doc { 1018 d := make([]pretty.Doc, len(*node)) 1019 for i := range *node { 1020 d[i] = p.Doc(&(*node)[i]) 1021 } 1022 return p.commaSeparated(d...) 1023 } 1024 1025 func (node *CastExpr) doc(p *PrettyCfg) pretty.Doc { 1026 typ := p.formatType(node.Type) 1027 1028 switch node.SyntaxMode { 1029 case CastPrepend: 1030 // This is a special case for things like INTERVAL '1s'. These only work 1031 // with string constats; if the underlying expression was changed, we fall 1032 // back to the short syntax. 1033 if _, ok := node.Expr.(*StrVal); ok { 1034 return pretty.Fold(pretty.Concat, 1035 typ, 1036 pretty.Text(" "), 1037 p.Doc(node.Expr), 1038 ) 1039 } 1040 fallthrough 1041 case CastShort: 1042 if typ, ok := GetStaticallyKnownType(node.Type); ok { 1043 switch typ.Family() { 1044 case types.JsonFamily: 1045 if sv, ok := node.Expr.(*StrVal); ok && p.JSONFmt { 1046 return p.jsonCast(sv, "::", typ) 1047 } 1048 } 1049 } 1050 return pretty.Fold(pretty.Concat, 1051 p.exprDocWithParen(node.Expr), 1052 pretty.Text("::"), 1053 typ, 1054 ) 1055 default: 1056 if nTyp, ok := GetStaticallyKnownType(node.Type); ok && nTyp.Family() == types.CollatedStringFamily { 1057 // COLLATE clause needs to go after CAST expression, so create 1058 // equivalent string type without the locale to get name of string 1059 // type without the COLLATE. 1060 strTyp := types.MakeScalar( 1061 types.StringFamily, 1062 nTyp.Oid(), 1063 nTyp.Precision(), 1064 nTyp.Width(), 1065 "", /* locale */ 1066 ) 1067 typ = pretty.Text(strTyp.SQLString()) 1068 } 1069 1070 ret := pretty.Fold(pretty.Concat, 1071 pretty.Keyword("CAST"), 1072 p.bracket( 1073 "(", 1074 p.nestUnder( 1075 p.Doc(node.Expr), 1076 pretty.Concat( 1077 p.keywordWithText("", "AS", " "), 1078 typ, 1079 ), 1080 ), 1081 ")", 1082 ), 1083 ) 1084 1085 if nTyp, ok := GetStaticallyKnownType(node.Type); ok && nTyp.Family() == types.CollatedStringFamily { 1086 ret = pretty.Fold(pretty.ConcatSpace, 1087 ret, 1088 pretty.Keyword("COLLATE"), 1089 pretty.Text(nTyp.Locale())) 1090 } 1091 return ret 1092 } 1093 } 1094 1095 func (node *ValuesClause) doc(p *PrettyCfg) pretty.Doc { 1096 return p.rlTable(node.docTable(p)...) 1097 } 1098 1099 func (node *ValuesClause) docTable(p *PrettyCfg) []pretty.TableRow { 1100 d := make([]pretty.Doc, len(node.Rows)) 1101 for i := range node.Rows { 1102 d[i] = p.bracket("(", p.Doc(&node.Rows[i]), ")") 1103 } 1104 return []pretty.TableRow{p.row("VALUES", p.commaSeparated(d...))} 1105 } 1106 1107 func (node *StatementSource) doc(p *PrettyCfg) pretty.Doc { 1108 return p.bracket("[", p.Doc(node.Statement), "]") 1109 } 1110 1111 func (node *RowsFromExpr) doc(p *PrettyCfg) pretty.Doc { 1112 if p.Simplify && len(node.Items) == 1 { 1113 return p.Doc(node.Items[0]) 1114 } 1115 return p.bracketKeyword("ROWS FROM", " (", p.Doc(&node.Items), ")", "") 1116 } 1117 1118 func (node *Array) doc(p *PrettyCfg) pretty.Doc { 1119 return p.bracketKeyword("ARRAY", "[", p.Doc(&node.Exprs), "]", "") 1120 } 1121 1122 func (node *Tuple) doc(p *PrettyCfg) pretty.Doc { 1123 exprDoc := p.Doc(&node.Exprs) 1124 if len(node.Exprs) == 1 { 1125 exprDoc = pretty.Concat(exprDoc, pretty.Text(",")) 1126 } 1127 d := p.bracket("(", exprDoc, ")") 1128 if len(node.Labels) > 0 { 1129 labels := make([]pretty.Doc, len(node.Labels)) 1130 for i := range node.Labels { 1131 n := &node.Labels[i] 1132 labels[i] = p.Doc((*Name)(n)) 1133 } 1134 d = p.bracket("(", pretty.Stack( 1135 d, 1136 p.nestUnder(pretty.Keyword("AS"), p.commaSeparated(labels...)), 1137 ), ")") 1138 } 1139 return d 1140 } 1141 1142 func (node *UpdateExprs) doc(p *PrettyCfg) pretty.Doc { 1143 d := make([]pretty.Doc, len(*node)) 1144 for i, n := range *node { 1145 d[i] = p.Doc(n) 1146 } 1147 return p.commaSeparated(d...) 1148 } 1149 1150 func (p *PrettyCfg) exprDocWithParen(e Expr) pretty.Doc { 1151 if _, ok := e.(operatorExpr); ok { 1152 return p.bracket("(", p.Doc(e), ")") 1153 } 1154 return p.Doc(e) 1155 } 1156 1157 func (node *Update) doc(p *PrettyCfg) pretty.Doc { 1158 items := make([]pretty.TableRow, 0, 8) 1159 items = append(items, 1160 node.With.docRow(p), 1161 p.row("UPDATE", p.Doc(node.Table)), 1162 p.row("SET", p.Doc(&node.Exprs))) 1163 if len(node.From) > 0 { 1164 items = append(items, 1165 p.row("FROM", p.Doc(&node.From))) 1166 } 1167 items = append(items, 1168 node.Where.docRow(p), 1169 node.OrderBy.docRow(p)) 1170 items = append(items, node.Limit.docTable(p)...) 1171 items = append(items, p.docReturning(node.Returning)) 1172 return p.rlTable(items...) 1173 } 1174 1175 func (node *Delete) doc(p *PrettyCfg) pretty.Doc { 1176 items := make([]pretty.TableRow, 0, 7) 1177 items = append(items, 1178 node.With.docRow(p)) 1179 tableLbl := "DELETE FROM" 1180 batch := node.Batch 1181 if batch != nil { 1182 tableLbl = "FROM" 1183 items = append(items, 1184 p.row("DELETE", p.Doc(batch))) 1185 } 1186 items = append(items, 1187 p.row(tableLbl, p.Doc(node.Table))) 1188 if len(node.Using) > 0 { 1189 items = append(items, p.row("USING", p.Doc(&node.Using))) 1190 } 1191 items = append(items, 1192 node.Where.docRow(p), 1193 node.OrderBy.docRow(p)) 1194 items = append(items, node.Limit.docTable(p)...) 1195 items = append(items, p.docReturning(node.Returning)) 1196 return p.rlTable(items...) 1197 } 1198 1199 func (p *PrettyCfg) docReturning(node ReturningClause) pretty.TableRow { 1200 switch r := node.(type) { 1201 case *NoReturningClause: 1202 return p.row("", nil) 1203 case *ReturningNothing: 1204 return p.row("RETURNING", pretty.Keyword("NOTHING")) 1205 case *ReturningExprs: 1206 return p.row("RETURNING", p.Doc((*SelectExprs)(r))) 1207 default: 1208 panic(errors.AssertionFailedf("unhandled case: %T", node)) 1209 } 1210 } 1211 1212 func (node *Order) doc(p *PrettyCfg) pretty.Doc { 1213 var d pretty.Doc 1214 if node.OrderType == OrderByColumn { 1215 d = p.Doc(node.Expr) 1216 } else { 1217 if node.Index == "" { 1218 d = pretty.ConcatSpace( 1219 pretty.Keyword("PRIMARY KEY"), 1220 p.Doc(&node.Table), 1221 ) 1222 } else { 1223 d = pretty.ConcatSpace( 1224 pretty.Keyword("INDEX"), 1225 pretty.Fold(pretty.Concat, 1226 p.Doc(&node.Table), 1227 pretty.Text("@"), 1228 p.Doc(&node.Index), 1229 ), 1230 ) 1231 } 1232 } 1233 if node.Direction != DefaultDirection { 1234 d = p.nestUnder(d, pretty.Text(node.Direction.String())) 1235 } 1236 if node.NullsOrder != DefaultNullsOrder { 1237 d = p.nestUnder(d, pretty.Text(node.NullsOrder.String())) 1238 } 1239 return d 1240 } 1241 1242 func (node *UpdateExpr) doc(p *PrettyCfg) pretty.Doc { 1243 d := p.Doc(&node.Names) 1244 if node.Tuple { 1245 d = p.bracket("(", d, ")") 1246 } 1247 e := node.Expr 1248 if p.Simplify { 1249 e = StripParens(e) 1250 } 1251 return p.nestUnder(d, pretty.ConcatSpace(pretty.Text("="), p.Doc(e))) 1252 } 1253 1254 func (node *CreateTable) doc(p *PrettyCfg) pretty.Doc { 1255 // Final layout: 1256 // 1257 // CREATE [TEMP | UNLOGGED] TABLE [IF NOT EXISTS] name ( .... ) [AS] 1258 // [SELECT ...] - for CREATE TABLE AS 1259 // [INTERLEAVE ...] 1260 // [PARTITION BY ...] 1261 // 1262 title := pretty.Keyword("CREATE") 1263 switch node.Persistence { 1264 case PersistenceTemporary: 1265 title = pretty.ConcatSpace(title, pretty.Keyword("TEMPORARY")) 1266 case PersistenceUnlogged: 1267 title = pretty.ConcatSpace(title, pretty.Keyword("UNLOGGED")) 1268 } 1269 title = pretty.ConcatSpace(title, pretty.Keyword("TABLE")) 1270 if node.IfNotExists { 1271 title = pretty.ConcatSpace(title, pretty.Keyword("IF NOT EXISTS")) 1272 } 1273 title = pretty.ConcatSpace(title, p.Doc(&node.Table)) 1274 1275 if node.As() { 1276 if len(node.Defs) > 0 { 1277 title = pretty.ConcatSpace(title, 1278 p.bracket("(", p.Doc(&node.Defs), ")")) 1279 } 1280 if node.StorageParams != nil { 1281 title = pretty.ConcatSpace(title, pretty.Keyword("WITH")) 1282 title = pretty.ConcatSpace(title, p.bracket(`(`, p.Doc(&node.StorageParams), `)`)) 1283 } 1284 title = pretty.ConcatSpace(title, pretty.Keyword("AS")) 1285 } else { 1286 title = pretty.ConcatSpace(title, 1287 p.bracket("(", p.Doc(&node.Defs), ")"), 1288 ) 1289 } 1290 1291 clauses := make([]pretty.Doc, 0, 4) 1292 if node.As() { 1293 clauses = append(clauses, p.Doc(node.AsSource)) 1294 } 1295 if node.PartitionByTable != nil { 1296 clauses = append(clauses, p.Doc(node.PartitionByTable)) 1297 } 1298 if node.StorageParams != nil && !node.As() { 1299 clauses = append( 1300 clauses, 1301 pretty.ConcatSpace( 1302 pretty.Keyword(`WITH`), 1303 p.bracket(`(`, p.Doc(&node.StorageParams), `)`), 1304 ), 1305 ) 1306 } 1307 if node.Locality != nil { 1308 clauses = append(clauses, p.Doc(node.Locality)) 1309 } 1310 if len(clauses) == 0 { 1311 return title 1312 } 1313 return p.nestUnder(title, pretty.Group(pretty.Stack(clauses...))) 1314 } 1315 1316 func (node *CreateView) doc(p *PrettyCfg) pretty.Doc { 1317 // Final layout: 1318 // 1319 // CREATE [TEMP] VIEW name ( ... ) AS 1320 // SELECT ... 1321 // 1322 title := pretty.Keyword("CREATE") 1323 if node.Replace { 1324 title = pretty.ConcatSpace(title, pretty.Keyword("OR REPLACE")) 1325 } 1326 if node.Persistence == PersistenceTemporary { 1327 title = pretty.ConcatSpace(title, pretty.Keyword("TEMPORARY")) 1328 } 1329 if node.Materialized { 1330 title = pretty.ConcatSpace(title, pretty.Keyword("MATERIALIZED")) 1331 } 1332 title = pretty.ConcatSpace(title, pretty.Keyword("VIEW")) 1333 if node.IfNotExists { 1334 title = pretty.ConcatSpace(title, pretty.Keyword("IF NOT EXISTS")) 1335 } 1336 d := pretty.ConcatSpace( 1337 title, 1338 p.Doc(&node.Name), 1339 ) 1340 if len(node.ColumnNames) > 0 { 1341 d = pretty.ConcatSpace( 1342 d, 1343 p.bracket("(", p.Doc(&node.ColumnNames), ")"), 1344 ) 1345 } 1346 d = p.nestUnder( 1347 pretty.ConcatSpace(d, pretty.Keyword("AS")), 1348 p.Doc(node.AsSource), 1349 ) 1350 if node.Materialized && node.WithData { 1351 d = pretty.ConcatSpace(d, pretty.Keyword("WITH DATA")) 1352 } else if node.Materialized && !node.WithData { 1353 d = pretty.ConcatSpace(d, pretty.Keyword("WITH NO DATA")) 1354 } 1355 return d 1356 } 1357 1358 func (node *TableDefs) doc(p *PrettyCfg) pretty.Doc { 1359 // This groups column definitions using a table to get alignment of 1360 // column names, and separately comma-joins groups of column definitions 1361 // with constraint definitions. 1362 1363 defs := *node 1364 colDefRows := make([]pretty.TableRow, 0, len(defs)) 1365 items := make([]pretty.Doc, 0, len(defs)) 1366 1367 for i := 0; i < len(defs); i++ { 1368 if _, ok := defs[i].(*ColumnTableDef); ok { 1369 // Group all the subsequent column definitions into a table. 1370 j := i 1371 colDefRows = colDefRows[:0] 1372 for ; j < len(defs); j++ { 1373 cdef, ok := defs[j].(*ColumnTableDef) 1374 if !ok { 1375 break 1376 } 1377 colDefRows = append(colDefRows, cdef.docRow(p)) 1378 } 1379 // Let the outer loop pick up where we left. 1380 i = j - 1 1381 1382 // At this point the column definitions form a table, but the comma 1383 // is missing from each row. We need to add it here. However we 1384 // need to be careful. Since we're going to add a comma between the 1385 // set of all column definitions and the other table definitions 1386 // below (via commaSeparated), we need to ensure the last row does 1387 // not get a comma. 1388 for j = 0; j < len(colDefRows)-1; j++ { 1389 colDefRows[j].Doc = pretty.Concat(colDefRows[j].Doc, pretty.Text(",")) 1390 } 1391 items = append(items, p.llTable(pretty.Text, colDefRows...)) 1392 } else { 1393 // Not a column definition, just process normally. 1394 items = append(items, p.Doc(defs[i])) 1395 } 1396 } 1397 1398 return p.commaSeparated(items...) 1399 } 1400 1401 func (node *CaseExpr) doc(p *PrettyCfg) pretty.Doc { 1402 d := make([]pretty.Doc, 0, len(node.Whens)+3) 1403 c := pretty.Keyword("CASE") 1404 if node.Expr != nil { 1405 c = pretty.Group(pretty.ConcatSpace(c, p.Doc(node.Expr))) 1406 } 1407 d = append(d, c) 1408 for _, when := range node.Whens { 1409 d = append(d, p.Doc(when)) 1410 } 1411 if node.Else != nil { 1412 d = append(d, pretty.Group(pretty.ConcatSpace( 1413 pretty.Keyword("ELSE"), 1414 p.Doc(node.Else), 1415 ))) 1416 } 1417 d = append(d, pretty.Keyword("END")) 1418 return pretty.Stack(d...) 1419 } 1420 1421 func (node *When) doc(p *PrettyCfg) pretty.Doc { 1422 return pretty.Group(pretty.ConcatLine( 1423 pretty.Group(pretty.ConcatSpace( 1424 pretty.Keyword("WHEN"), 1425 p.Doc(node.Cond), 1426 )), 1427 pretty.Group(pretty.ConcatSpace( 1428 pretty.Keyword("THEN"), 1429 p.Doc(node.Val), 1430 )), 1431 )) 1432 } 1433 1434 func (node *UnionClause) doc(p *PrettyCfg) pretty.Doc { 1435 op := node.Type.String() 1436 if node.All { 1437 op += " ALL" 1438 } 1439 return pretty.Stack(p.Doc(node.Left), p.nestUnder(pretty.Keyword(op), p.Doc(node.Right))) 1440 } 1441 1442 func (node *IfErrExpr) doc(p *PrettyCfg) pretty.Doc { 1443 var s string 1444 if node.Else != nil { 1445 s = "IFERROR" 1446 } else { 1447 s = "ISERROR" 1448 } 1449 d := []pretty.Doc{p.Doc(node.Cond)} 1450 if node.Else != nil { 1451 d = append(d, p.Doc(node.Else)) 1452 } 1453 if node.ErrCode != nil { 1454 d = append(d, p.Doc(node.ErrCode)) 1455 } 1456 return p.bracketKeyword(s, "(", p.commaSeparated(d...), ")", "") 1457 } 1458 1459 func (node *IfExpr) doc(p *PrettyCfg) pretty.Doc { 1460 return p.bracketKeyword("IF", "(", 1461 p.commaSeparated( 1462 p.Doc(node.Cond), 1463 p.Doc(node.True), 1464 p.Doc(node.Else), 1465 ), ")", "") 1466 } 1467 1468 func (node *NullIfExpr) doc(p *PrettyCfg) pretty.Doc { 1469 return p.bracketKeyword("NULLIF", "(", 1470 p.commaSeparated( 1471 p.Doc(node.Expr1), 1472 p.Doc(node.Expr2), 1473 ), ")", "") 1474 } 1475 1476 func (node *PartitionByTable) doc(p *PrettyCfg) pretty.Doc { 1477 // Final layout: 1478 // 1479 // PARTITION [ALL] BY NOTHING 1480 // 1481 // PARTITION [ALL] BY LIST (...) 1482 // ( ..values.. ) 1483 // 1484 // PARTITION [ALL] BY RANGE (...) 1485 // ( ..values.. ) 1486 var kw string 1487 kw = `PARTITION ` 1488 if node.All { 1489 kw += `ALL ` 1490 } 1491 return node.PartitionBy.docInner(p, kw+`BY `) 1492 } 1493 1494 func (node *PartitionBy) doc(p *PrettyCfg) pretty.Doc { 1495 // Final layout: 1496 // 1497 // PARTITION BY NOTHING 1498 // 1499 // PARTITION BY LIST (...) 1500 // ( ..values.. ) 1501 // 1502 // PARTITION BY RANGE (...) 1503 // ( ..values.. ) 1504 return node.docInner(p, `PARTITION BY `) 1505 } 1506 1507 func (node *PartitionBy) docInner(p *PrettyCfg, kw string) pretty.Doc { 1508 if node == nil { 1509 return pretty.Keyword(kw + `NOTHING`) 1510 } 1511 if len(node.List) > 0 { 1512 kw += `LIST` 1513 } else if len(node.Range) > 0 { 1514 kw += `RANGE` 1515 } 1516 title := pretty.ConcatSpace(pretty.Keyword(kw), 1517 p.bracket("(", p.Doc(&node.Fields), ")")) 1518 1519 inner := make([]pretty.Doc, 0, len(node.List)+len(node.Range)) 1520 for _, v := range node.List { 1521 inner = append(inner, p.Doc(&v)) 1522 } 1523 for _, v := range node.Range { 1524 inner = append(inner, p.Doc(&v)) 1525 } 1526 return p.nestUnder(title, 1527 p.bracket("(", p.commaSeparated(inner...), ")"), 1528 ) 1529 } 1530 1531 func (node *Locality) doc(p *PrettyCfg) pretty.Doc { 1532 // Final layout: 1533 // 1534 // LOCALITY [GLOBAL | REGIONAL BY [TABLE [IN [PRIMARY REGION|region]]|ROW]] 1535 localityKW := pretty.Keyword("LOCALITY") 1536 switch node.LocalityLevel { 1537 case LocalityLevelGlobal: 1538 return pretty.ConcatSpace(localityKW, pretty.Keyword("GLOBAL")) 1539 case LocalityLevelRow: 1540 ret := pretty.ConcatSpace(localityKW, pretty.Keyword("REGIONAL BY ROW")) 1541 if node.RegionalByRowColumn != "" { 1542 return pretty.ConcatSpace( 1543 ret, 1544 pretty.ConcatSpace( 1545 pretty.Keyword("AS"), 1546 p.Doc(&node.RegionalByRowColumn), 1547 ), 1548 ) 1549 } 1550 return ret 1551 case LocalityLevelTable: 1552 byTable := pretty.ConcatSpace(localityKW, pretty.Keyword("REGIONAL BY TABLE IN")) 1553 if node.TableRegion == "" { 1554 return pretty.ConcatSpace( 1555 byTable, 1556 pretty.Keyword("PRIMARY REGION"), 1557 ) 1558 } 1559 return pretty.ConcatSpace( 1560 byTable, 1561 p.Doc(&node.TableRegion), 1562 ) 1563 } 1564 panic(fmt.Sprintf("unknown locality: %v", *node)) 1565 } 1566 1567 func (node *ListPartition) doc(p *PrettyCfg) pretty.Doc { 1568 // Final layout: 1569 // 1570 // PARTITION name 1571 // VALUES IN ( ... ) 1572 // [ .. subpartition ..] 1573 // 1574 title := pretty.ConcatSpace(pretty.Keyword("PARTITION"), p.Doc(&node.Name)) 1575 1576 clauses := make([]pretty.Doc, 1, 2) 1577 clauses[0] = pretty.ConcatSpace( 1578 pretty.Keyword("VALUES IN"), 1579 p.bracket("(", p.Doc(&node.Exprs), ")"), 1580 ) 1581 if node.Subpartition != nil { 1582 clauses = append(clauses, p.Doc(node.Subpartition)) 1583 } 1584 return p.nestUnder(title, pretty.Group(pretty.Stack(clauses...))) 1585 } 1586 1587 func (node *RangePartition) doc(p *PrettyCfg) pretty.Doc { 1588 // Final layout: 1589 // 1590 // PARTITION name 1591 // VALUES FROM (...) 1592 // TO (...) 1593 // [ .. subpartition ..] 1594 // 1595 title := pretty.ConcatSpace( 1596 pretty.Keyword("PARTITION"), 1597 p.Doc(&node.Name), 1598 ) 1599 1600 clauses := make([]pretty.Doc, 2, 3) 1601 clauses[0] = pretty.ConcatSpace( 1602 pretty.Keyword("VALUES FROM"), 1603 p.bracket("(", p.Doc(&node.From), ")")) 1604 clauses[1] = pretty.ConcatSpace( 1605 pretty.Keyword("TO"), 1606 p.bracket("(", p.Doc(&node.To), ")")) 1607 1608 if node.Subpartition != nil { 1609 clauses = append(clauses, p.Doc(node.Subpartition)) 1610 } 1611 1612 return p.nestUnder(title, pretty.Group(pretty.Stack(clauses...))) 1613 } 1614 1615 func (node *ShardedIndexDef) doc(p *PrettyCfg) pretty.Doc { 1616 // Final layout: 1617 // 1618 // USING HASH [WITH BUCKET_COUNT = bucket_count] 1619 // 1620 if _, ok := node.ShardBuckets.(DefaultVal); ok { 1621 return pretty.Keyword("USING HASH") 1622 } 1623 parts := []pretty.Doc{ 1624 pretty.Keyword("USING HASH WITH BUCKET_COUNT = "), 1625 p.Doc(node.ShardBuckets), 1626 } 1627 return pretty.Fold(pretty.ConcatSpace, parts...) 1628 } 1629 1630 func (node *CreateIndex) doc(p *PrettyCfg) pretty.Doc { 1631 // Final layout: 1632 // CREATE [UNIQUE] [INVERTED] INDEX [name] 1633 // ON tbl (cols...) 1634 // [STORING ( ... )] 1635 // [INTERLEAVE ...] 1636 // [PARTITION BY ...] 1637 // [WITH ...] 1638 // [WHERE ...] 1639 // [NOT VISIBLE | VISIBILITY ...] 1640 // 1641 title := make([]pretty.Doc, 0, 7) 1642 title = append(title, pretty.Keyword("CREATE")) 1643 if node.Unique { 1644 title = append(title, pretty.Keyword("UNIQUE")) 1645 } 1646 if node.Inverted { 1647 title = append(title, pretty.Keyword("INVERTED")) 1648 } 1649 title = append(title, pretty.Keyword("INDEX")) 1650 if node.Concurrently { 1651 title = append(title, pretty.Keyword("CONCURRENTLY")) 1652 } 1653 if node.IfNotExists { 1654 title = append(title, pretty.Keyword("IF NOT EXISTS")) 1655 } 1656 if node.Name != "" { 1657 title = append(title, p.Doc(&node.Name)) 1658 } 1659 1660 clauses := make([]pretty.Doc, 0, 7) 1661 clauses = append(clauses, pretty.Fold(pretty.ConcatSpace, 1662 pretty.Keyword("ON"), 1663 p.Doc(&node.Table), 1664 p.bracket("(", p.Doc(&node.Columns), ")"))) 1665 1666 if node.Sharded != nil { 1667 clauses = append(clauses, p.Doc(node.Sharded)) 1668 } 1669 if len(node.Storing) > 0 { 1670 clauses = append(clauses, p.bracketKeyword( 1671 "STORING", " (", 1672 p.Doc(&node.Storing), 1673 ")", "", 1674 )) 1675 } 1676 if node.PartitionByIndex != nil { 1677 clauses = append(clauses, p.Doc(node.PartitionByIndex)) 1678 } 1679 if node.StorageParams != nil { 1680 clauses = append(clauses, p.bracketKeyword( 1681 "WITH", " (", 1682 p.Doc(&node.StorageParams), 1683 ")", "", 1684 )) 1685 } 1686 if node.Predicate != nil { 1687 clauses = append(clauses, p.nestUnder(pretty.Keyword("WHERE"), p.Doc(node.Predicate))) 1688 } 1689 switch { 1690 case node.Invisibility.FloatProvided: 1691 clauses = append(clauses, 1692 pretty.Keyword(" VISIBILITY "+fmt.Sprintf("%.2f", 1-node.Invisibility.Value))) 1693 case node.Invisibility.Value == 1.0: 1694 clauses = append(clauses, pretty.Keyword(" NOT VISIBLE")) 1695 } 1696 return p.nestUnder( 1697 pretty.Fold(pretty.ConcatSpace, title...), 1698 pretty.Group(pretty.Stack(clauses...))) 1699 } 1700 1701 func (node *FamilyTableDef) doc(p *PrettyCfg) pretty.Doc { 1702 // Final layout: 1703 // FAMILY [name] (columns...) 1704 // 1705 d := pretty.Keyword("FAMILY") 1706 if node.Name != "" { 1707 d = pretty.ConcatSpace(d, p.Doc(&node.Name)) 1708 } 1709 return pretty.ConcatSpace(d, p.bracket("(", p.Doc(&node.Columns), ")")) 1710 } 1711 1712 func (node *LikeTableDef) doc(p *PrettyCfg) pretty.Doc { 1713 d := pretty.Keyword("LIKE") 1714 d = pretty.ConcatSpace(d, p.Doc(&node.Name)) 1715 for _, opt := range node.Options { 1716 word := "INCLUDING" 1717 if opt.Excluded { 1718 word = "EXCLUDING" 1719 } 1720 d = pretty.ConcatSpace(d, pretty.Keyword(word)) 1721 d = pretty.ConcatSpace(d, pretty.Keyword(opt.Opt.String())) 1722 } 1723 return d 1724 } 1725 1726 func (node *IndexTableDef) doc(p *PrettyCfg) pretty.Doc { 1727 // Final layout: 1728 // [INVERTED] INDEX [name] (columns...) 1729 // [STORING ( ... )] 1730 // [INTERLEAVE ...] 1731 // [PARTITION BY ...] 1732 // [WHERE ...] 1733 // [NOT VISIBLE | VISIBILITY ...] 1734 // 1735 title := pretty.Keyword("INDEX") 1736 if node.Name != "" { 1737 title = pretty.ConcatSpace(title, p.Doc(&node.Name)) 1738 } 1739 if node.Inverted { 1740 title = pretty.ConcatSpace(pretty.Keyword("INVERTED"), title) 1741 } 1742 title = pretty.ConcatSpace(title, p.bracket("(", p.Doc(&node.Columns), ")")) 1743 1744 clauses := make([]pretty.Doc, 0, 6) 1745 if node.Sharded != nil { 1746 clauses = append(clauses, p.Doc(node.Sharded)) 1747 } 1748 if node.Storing != nil { 1749 clauses = append(clauses, p.bracketKeyword( 1750 "STORING", "(", 1751 p.Doc(&node.Storing), 1752 ")", "")) 1753 } 1754 if node.PartitionByIndex != nil { 1755 clauses = append(clauses, p.Doc(node.PartitionByIndex)) 1756 } 1757 if node.StorageParams != nil { 1758 clauses = append( 1759 clauses, 1760 p.bracketKeyword("WITH", "(", p.Doc(&node.StorageParams), ")", ""), 1761 ) 1762 } 1763 if node.Predicate != nil { 1764 clauses = append(clauses, p.nestUnder(pretty.Keyword("WHERE"), p.Doc(node.Predicate))) 1765 } 1766 switch { 1767 case node.Invisibility.FloatProvided: 1768 clauses = append(clauses, 1769 pretty.Keyword(" VISIBILITY "+fmt.Sprintf("%.2f", 1-node.Invisibility.Value))) 1770 case node.Invisibility.Value == 1.0: 1771 clauses = append(clauses, pretty.Keyword(" NOT VISIBLE")) 1772 } 1773 if len(clauses) == 0 { 1774 return title 1775 } 1776 return p.nestUnder(title, pretty.Group(pretty.Stack(clauses...))) 1777 } 1778 1779 func (node *UniqueConstraintTableDef) doc(p *PrettyCfg) pretty.Doc { 1780 // Final layout: 1781 // [CONSTRAINT name] 1782 // [PRIMARY KEY|UNIQUE [WITHOUT INDEX]] ( ... ) 1783 // [STORING ( ... )] 1784 // [INTERLEAVE ...] 1785 // [PARTITION BY ...] 1786 // [WHERE ...] 1787 // [NOT VISIBLE | VISIBILITY ...] 1788 // 1789 // or (no constraint name): 1790 // 1791 // [PRIMARY KEY|UNIQUE [WITHOUT INDEX]] ( ... ) 1792 // [STORING ( ... )] 1793 // [INTERLEAVE ...] 1794 // [PARTITION BY ...] 1795 // [WHERE ...] 1796 // [NOT VISIBLE | VISIBILITY ...] 1797 // 1798 clauses := make([]pretty.Doc, 0, 6) 1799 var title pretty.Doc 1800 if node.PrimaryKey { 1801 title = pretty.Keyword("PRIMARY KEY") 1802 } else { 1803 title = pretty.Keyword("UNIQUE") 1804 if node.WithoutIndex { 1805 title = pretty.ConcatSpace(title, pretty.Keyword("WITHOUT INDEX")) 1806 } 1807 } 1808 title = pretty.ConcatSpace(title, p.bracket("(", p.Doc(&node.Columns), ")")) 1809 if node.Name != "" { 1810 clauses = append(clauses, title) 1811 title = pretty.ConcatSpace(pretty.Keyword("CONSTRAINT"), p.Doc(&node.Name)) 1812 } 1813 if node.Sharded != nil { 1814 clauses = append(clauses, p.Doc(node.Sharded)) 1815 } 1816 if node.Storing != nil { 1817 clauses = append(clauses, p.bracketKeyword( 1818 "STORING", "(", 1819 p.Doc(&node.Storing), 1820 ")", "")) 1821 } 1822 1823 if node.PartitionByIndex != nil { 1824 clauses = append(clauses, p.Doc(node.PartitionByIndex)) 1825 } 1826 if node.Predicate != nil { 1827 clauses = append(clauses, p.nestUnder(pretty.Keyword("WHERE"), p.Doc(node.Predicate))) 1828 } 1829 switch { 1830 case node.Invisibility.FloatProvided: 1831 clauses = append(clauses, 1832 pretty.Keyword(" VISIBILITY "+fmt.Sprintf("%.2f", 1-node.Invisibility.Value))) 1833 case node.Invisibility.Value == 1.0: 1834 clauses = append(clauses, pretty.Keyword(" NOT VISIBLE")) 1835 } 1836 if node.StorageParams != nil { 1837 clauses = append(clauses, p.bracketKeyword( 1838 "WITH", "(", 1839 p.Doc(&node.StorageParams), 1840 ")", "")) 1841 } 1842 1843 if len(clauses) == 0 { 1844 return title 1845 } 1846 return p.nestUnder(title, pretty.Group(pretty.Stack(clauses...))) 1847 } 1848 1849 func (node *ForeignKeyConstraintTableDef) doc(p *PrettyCfg) pretty.Doc { 1850 // Final layout: 1851 // [CONSTRAINT name] 1852 // FOREIGN KEY (...) 1853 // REFERENCES tbl (...) 1854 // [MATCH ...] 1855 // [ACTIONS ...] 1856 // 1857 // or (no constraint name): 1858 // 1859 // FOREIGN KEY (...) 1860 // REFERENCES tbl [(...)] 1861 // [MATCH ...] 1862 // [ACTIONS ...] 1863 // 1864 clauses := make([]pretty.Doc, 0, 4) 1865 title := pretty.ConcatSpace( 1866 pretty.Keyword("FOREIGN KEY"), 1867 p.bracket("(", p.Doc(&node.FromCols), ")")) 1868 1869 if node.Name != "" { 1870 clauses = append(clauses, title) 1871 title = pretty.ConcatSpace(pretty.Keyword("CONSTRAINT"), p.Doc(&node.Name)) 1872 } 1873 1874 ref := pretty.ConcatSpace( 1875 pretty.Keyword("REFERENCES"), p.Doc(&node.Table)) 1876 if len(node.ToCols) > 0 { 1877 ref = pretty.ConcatSpace(ref, p.bracket("(", p.Doc(&node.ToCols), ")")) 1878 } 1879 clauses = append(clauses, ref) 1880 1881 if node.Match != MatchSimple { 1882 clauses = append(clauses, pretty.Keyword(node.Match.String())) 1883 } 1884 1885 if actions := p.Doc(&node.Actions); ref != pretty.Nil { 1886 clauses = append(clauses, actions) 1887 } 1888 1889 return p.nestUnder(title, pretty.Group(pretty.Stack(clauses...))) 1890 } 1891 1892 func (p *PrettyCfg) maybePrependConstraintName(constraintName *Name, d pretty.Doc) pretty.Doc { 1893 if *constraintName != "" { 1894 return pretty.Fold(pretty.ConcatSpace, 1895 pretty.Keyword("CONSTRAINT"), 1896 p.Doc(constraintName), 1897 d) 1898 } 1899 return d 1900 } 1901 1902 func (node *ColumnTableDef) doc(p *PrettyCfg) pretty.Doc { 1903 return p.unrow(node.docRow(p)) 1904 } 1905 1906 func (node *ColumnTableDef) docRow(p *PrettyCfg) pretty.TableRow { 1907 // Final layout: 1908 // colname 1909 // type 1910 // [AS ( ... ) STORED] 1911 // [GENERATED {ALWAYS|BY DEFAULT} AS IDENTITY] 1912 // [[CREATE [IF NOT EXISTS]] FAMILY [name]] 1913 // [[CONSTRAINT name] DEFAULT expr] 1914 // [[CONSTRAINT name] {NULL|NOT NULL}] 1915 // [[CONSTRAINT name] {PRIMARY KEY|UNIQUE [WITHOUT INDEX]}] 1916 // [[CONSTRAINT name] CHECK ...] 1917 // [[CONSTRAINT name] REFERENCES tbl (...) 1918 // [MATCH ...] 1919 // [ACTIONS ...] 1920 // ] 1921 // 1922 clauses := make([]pretty.Doc, 0, 14) 1923 1924 // Column type. 1925 // ColumnTableDef node type will not be specified if it represents a CREATE 1926 // TABLE ... AS query. 1927 if node.Type != nil { 1928 clauses = append(clauses, func() pretty.Doc { 1929 if name, replaced := node.replacedSerialTypeName(); replaced { 1930 return pretty.Text(name) 1931 } 1932 return p.formatType(node.Type) 1933 }()) 1934 } 1935 1936 // Compute expression (for computed columns). 1937 if node.IsComputed() { 1938 var typ string 1939 if node.Computed.Virtual { 1940 typ = "VIRTUAL" 1941 } else { 1942 typ = "STORED" 1943 } 1944 1945 clauses = append(clauses, pretty.ConcatSpace( 1946 pretty.Keyword("AS"), 1947 pretty.ConcatSpace( 1948 p.bracket("(", p.Doc(node.Computed.Expr), ")"), 1949 pretty.Keyword(typ), 1950 ), 1951 )) 1952 } 1953 1954 // GENERATED ALWAYS/BY DEFAULT AS IDENTITY constraint. 1955 if node.GeneratedIdentity.IsGeneratedAsIdentity { 1956 var generatedConstraint pretty.Doc 1957 switch node.GeneratedIdentity.GeneratedAsIdentityType { 1958 case GeneratedAlways: 1959 generatedConstraint = pretty.Keyword("GENERATED ALWAYS AS IDENTITY") 1960 case GeneratedByDefault: 1961 generatedConstraint = pretty.Keyword("GENERATED BY DEFAULT AS IDENTITY") 1962 } 1963 clauses = append(clauses, generatedConstraint) 1964 if node.GeneratedIdentity.SeqOptions != nil { 1965 const prettyFlags = FmtShowPasswords | FmtParsable 1966 curGenSeqOpts := node.GeneratedIdentity.SeqOptions 1967 txt := AsStringWithFlags(&curGenSeqOpts, prettyFlags) 1968 bracketedTxt := p.bracket("(", pretty.Text(strings.TrimSpace(txt)), ")") 1969 clauses = append(clauses, bracketedTxt) 1970 } 1971 } 1972 1973 // Column family. 1974 if node.HasColumnFamily() { 1975 d := pretty.Keyword("FAMILY") 1976 if node.Family.Name != "" { 1977 d = pretty.ConcatSpace(d, p.Doc(&node.Family.Name)) 1978 } 1979 if node.Family.Create { 1980 c := pretty.Keyword("CREATE") 1981 if node.Family.IfNotExists { 1982 c = pretty.ConcatSpace(c, pretty.Keyword("IF NOT EXISTS")) 1983 } 1984 d = pretty.ConcatSpace(c, d) 1985 } 1986 clauses = append(clauses, d) 1987 } 1988 1989 // DEFAULT constraint. 1990 if node.HasDefaultExpr() { 1991 clauses = append(clauses, p.maybePrependConstraintName(&node.DefaultExpr.ConstraintName, 1992 pretty.ConcatSpace(pretty.Keyword("DEFAULT"), p.Doc(node.DefaultExpr.Expr)))) 1993 } 1994 1995 // ON UPDATE expression. 1996 if node.HasOnUpdateExpr() { 1997 clauses = append(clauses, p.maybePrependConstraintName(&node.OnUpdateExpr.ConstraintName, 1998 pretty.ConcatSpace(pretty.Keyword("ON UPDATE"), p.Doc(node.OnUpdateExpr.Expr)))) 1999 } 2000 2001 // [NOT] VISIBLE constraint. 2002 if node.Hidden { 2003 hiddenConstraint := pretty.Keyword("NOT VISIBLE") 2004 clauses = append(clauses, p.maybePrependConstraintName(&node.Nullable.ConstraintName, hiddenConstraint)) 2005 } 2006 2007 // NULL/NOT NULL constraint. 2008 nConstraint := pretty.Nil 2009 switch node.Nullable.Nullability { 2010 case Null: 2011 nConstraint = pretty.Keyword("NULL") 2012 case NotNull: 2013 nConstraint = pretty.Keyword("NOT NULL") 2014 } 2015 if nConstraint != pretty.Nil { 2016 clauses = append(clauses, p.maybePrependConstraintName(&node.Nullable.ConstraintName, nConstraint)) 2017 } 2018 2019 // PRIMARY KEY / UNIQUE constraint. 2020 pkConstraint := pretty.Nil 2021 if node.PrimaryKey.IsPrimaryKey { 2022 pkConstraint = pretty.Keyword("PRIMARY KEY") 2023 } else if node.Unique.IsUnique { 2024 pkConstraint = pretty.Keyword("UNIQUE") 2025 if node.Unique.WithoutIndex { 2026 pkConstraint = pretty.ConcatSpace(pkConstraint, pretty.Keyword("WITHOUT INDEX")) 2027 } 2028 } 2029 if pkConstraint != pretty.Nil { 2030 clauses = append(clauses, p.maybePrependConstraintName(&node.Unique.ConstraintName, pkConstraint)) 2031 } 2032 2033 // Always prefer to output hash sharding bucket count as a storage param. 2034 pkStorageParams := node.PrimaryKey.StorageParams 2035 if node.PrimaryKey.Sharded { 2036 clauses = append(clauses, pretty.Keyword("USING HASH")) 2037 bcStorageParam := node.PrimaryKey.StorageParams.GetVal(`bucket_count`) 2038 if _, ok := node.PrimaryKey.ShardBuckets.(DefaultVal); !ok && bcStorageParam == nil { 2039 pkStorageParams = append( 2040 pkStorageParams, StorageParam{ 2041 Key: `bucket_count`, 2042 Value: node.PrimaryKey.ShardBuckets, 2043 }, 2044 ) 2045 } 2046 } 2047 if len(pkStorageParams) > 0 { 2048 clauses = append(clauses, p.bracketKeyword( 2049 "WITH", " (", 2050 p.Doc(&pkStorageParams), 2051 ")", "", 2052 )) 2053 } 2054 2055 // CHECK expressions/constraints. 2056 for _, checkExpr := range node.CheckExprs { 2057 clauses = append(clauses, p.maybePrependConstraintName(&checkExpr.ConstraintName, 2058 pretty.ConcatSpace(pretty.Keyword("CHECK"), p.bracket("(", p.Doc(checkExpr.Expr), ")")))) 2059 } 2060 2061 // FK constraints. 2062 if node.HasFKConstraint() { 2063 fkHead := pretty.ConcatSpace(pretty.Keyword("REFERENCES"), p.Doc(node.References.Table)) 2064 if node.References.Col != "" { 2065 fkHead = pretty.ConcatSpace(fkHead, p.bracket("(", p.Doc(&node.References.Col), ")")) 2066 } 2067 fkDetails := make([]pretty.Doc, 0, 2) 2068 // We omit MATCH SIMPLE because it is the default. 2069 if node.References.Match != MatchSimple { 2070 fkDetails = append(fkDetails, pretty.Keyword(node.References.Match.String())) 2071 } 2072 if ref := p.Doc(&node.References.Actions); ref != pretty.Nil { 2073 fkDetails = append(fkDetails, ref) 2074 } 2075 fk := fkHead 2076 if len(fkDetails) > 0 { 2077 fk = p.nestUnder(fk, pretty.Group(pretty.Stack(fkDetails...))) 2078 } 2079 clauses = append(clauses, p.maybePrependConstraintName(&node.References.ConstraintName, fk)) 2080 } 2081 2082 // Prevents an additional space from being appended at the end of every column 2083 // name in the case of CREATE TABLE ... AS query. The additional space is 2084 // being caused due to the absence of column type qualifiers in CTAS queries. 2085 // 2086 // TODO(adityamaru): Consult someone with more knowledge about the pretty 2087 // printer architecture to find a cleaner solution. 2088 var tblRow pretty.TableRow 2089 if node.Type == nil { 2090 tblRow = pretty.TableRow{ 2091 Label: node.Name.String(), 2092 Doc: pretty.Stack(clauses...), 2093 } 2094 } else { 2095 tblRow = pretty.TableRow{ 2096 Label: node.Name.String(), 2097 Doc: pretty.Group(pretty.Stack(clauses...)), 2098 } 2099 } 2100 2101 return tblRow 2102 } 2103 2104 func (p *PrettyCfg) formatType(typ ResolvableTypeReference) pretty.Doc { 2105 ctx := NewFmtCtx(p.fmtFlags()) 2106 ctx.FormatTypeReference(typ) 2107 return pretty.Text(strings.TrimSpace(ctx.String())) 2108 } 2109 2110 func (node *CheckConstraintTableDef) doc(p *PrettyCfg) pretty.Doc { 2111 // Final layout: 2112 // 2113 // CONSTRAINT name 2114 // CHECK (...) 2115 // 2116 // or (no constraint name): 2117 // 2118 // CHECK (...) 2119 // 2120 d := pretty.ConcatSpace(pretty.Keyword("CHECK"), 2121 p.bracket("(", p.Doc(node.Expr), ")")) 2122 2123 if node.Name != "" { 2124 d = p.nestUnder( 2125 pretty.ConcatSpace( 2126 pretty.Keyword("CONSTRAINT"), 2127 p.Doc(&node.Name), 2128 ), 2129 d, 2130 ) 2131 } 2132 return d 2133 } 2134 2135 func (node *ReferenceActions) doc(p *PrettyCfg) pretty.Doc { 2136 var docs []pretty.Doc 2137 if node.Delete != NoAction { 2138 docs = append(docs, 2139 pretty.Keyword("ON DELETE"), 2140 pretty.Keyword(node.Delete.String()), 2141 ) 2142 } 2143 if node.Update != NoAction { 2144 docs = append(docs, 2145 pretty.Keyword("ON UPDATE"), 2146 pretty.Keyword(node.Update.String()), 2147 ) 2148 } 2149 return pretty.Fold(pretty.ConcatSpace, docs...) 2150 } 2151 2152 func (node *Backup) doc(p *PrettyCfg) pretty.Doc { 2153 items := make([]pretty.TableRow, 0, 7) 2154 2155 items = append(items, p.row("BACKUP", pretty.Nil)) 2156 if node.Targets != nil { 2157 items = append(items, node.Targets.docRow(p)) 2158 } 2159 if node.Nested { 2160 if node.Subdir != nil { 2161 items = append(items, p.row("INTO ", p.Doc(node.Subdir))) 2162 items = append(items, p.row(" IN ", p.Doc(&node.To))) 2163 } else if node.AppendToLatest { 2164 items = append(items, p.row("INTO LATEST IN", p.Doc(&node.To))) 2165 } else { 2166 items = append(items, p.row("INTO", p.Doc(&node.To))) 2167 } 2168 } else { 2169 items = append(items, p.row("TO", p.Doc(&node.To))) 2170 } 2171 2172 if node.AsOf.Expr != nil { 2173 items = append(items, node.AsOf.docRow(p)) 2174 } 2175 if node.IncrementalFrom != nil { 2176 items = append(items, p.row("INCREMENTAL FROM", p.Doc(&node.IncrementalFrom))) 2177 } 2178 if !node.Options.IsDefault() { 2179 items = append(items, p.row("WITH", p.Doc(&node.Options))) 2180 } 2181 return p.rlTable(items...) 2182 } 2183 2184 func (node *Restore) doc(p *PrettyCfg) pretty.Doc { 2185 items := make([]pretty.TableRow, 0, 6) 2186 2187 items = append(items, p.row("RESTORE", pretty.Nil)) 2188 if node.DescriptorCoverage == RequestedDescriptors { 2189 items = append(items, node.Targets.docRow(p)) 2190 } 2191 from := make([]pretty.Doc, len(node.From)) 2192 for i := range node.From { 2193 from[i] = p.Doc(&node.From[i]) 2194 } 2195 if node.Subdir != nil { 2196 items = append(items, p.row("FROM", p.Doc(node.Subdir))) 2197 items = append(items, p.row("IN", p.commaSeparated(from...))) 2198 } else { 2199 items = append(items, p.row("FROM", p.commaSeparated(from...))) 2200 } 2201 2202 if node.AsOf.Expr != nil { 2203 items = append(items, node.AsOf.docRow(p)) 2204 } 2205 if !node.Options.IsDefault() { 2206 items = append(items, p.row("WITH", p.Doc(&node.Options))) 2207 } 2208 return p.rlTable(items...) 2209 } 2210 2211 func (node *BackupTargetList) doc(p *PrettyCfg) pretty.Doc { 2212 return p.unrow(node.docRow(p)) 2213 } 2214 2215 func (node *BackupTargetList) docRow(p *PrettyCfg) pretty.TableRow { 2216 if node.Databases != nil { 2217 return p.row("DATABASE", p.Doc(&node.Databases)) 2218 } 2219 if node.TenantID.Specified { 2220 return p.row("TENANT", p.Doc(&node.TenantID)) 2221 } 2222 if node.Tables.SequenceOnly { 2223 return p.row("SEQUENCE", p.Doc(&node.Tables.TablePatterns)) 2224 } 2225 return p.row("TABLE", p.Doc(&node.Tables.TablePatterns)) 2226 } 2227 2228 func (node *GrantTargetList) doc(p *PrettyCfg) pretty.Doc { 2229 return p.unrow(node.docRow(p)) 2230 } 2231 2232 func (node *GrantTargetList) docRow(p *PrettyCfg) pretty.TableRow { 2233 if node.Databases != nil { 2234 return p.row("DATABASE", p.Doc(&node.Databases)) 2235 } 2236 if node.Tables.SequenceOnly { 2237 return p.row("SEQUENCE", p.Doc(&node.Tables.TablePatterns)) 2238 } 2239 if node.ExternalConnections != nil { 2240 return p.row("EXTERNAL CONNECTION", p.Doc(&node.ExternalConnections)) 2241 } 2242 return p.row("TABLE", p.Doc(&node.Tables.TablePatterns)) 2243 } 2244 2245 func (node *AsOfClause) doc(p *PrettyCfg) pretty.Doc { 2246 return p.unrow(node.docRow(p)) 2247 } 2248 2249 func (node *AsOfClause) docRow(p *PrettyCfg) pretty.TableRow { 2250 return p.row("AS OF SYSTEM TIME", p.Doc(node.Expr)) 2251 } 2252 2253 func (node *KVOptions) doc(p *PrettyCfg) pretty.Doc { 2254 var opts []pretty.Doc 2255 for _, opt := range *node { 2256 d := p.Doc(&opt.Key) 2257 if opt.Value != nil { 2258 d = pretty.Fold(pretty.ConcatSpace, 2259 d, 2260 pretty.Text("="), 2261 p.Doc(opt.Value), 2262 ) 2263 } 2264 opts = append(opts, d) 2265 } 2266 return p.commaSeparated(opts...) 2267 } 2268 2269 func (node *Import) doc(p *PrettyCfg) pretty.Doc { 2270 items := make([]pretty.TableRow, 0, 5) 2271 items = append(items, p.row("IMPORT", pretty.Nil)) 2272 2273 if node.Bundle { 2274 if node.Table != nil { 2275 items = append(items, p.row("TABLE", p.Doc(node.Table))) 2276 items = append(items, p.row("FROM", pretty.Nil)) 2277 } 2278 items = append(items, p.row(node.FileFormat, p.Doc(&node.Files))) 2279 } else if node.Into { 2280 into := p.Doc(node.Table) 2281 if node.IntoCols != nil { 2282 into = p.nestUnder(into, p.bracket("(", p.Doc(&node.IntoCols), ")")) 2283 } 2284 items = append(items, p.row("INTO", into)) 2285 data := p.bracketKeyword( 2286 "DATA", " (", 2287 p.Doc(&node.Files), 2288 ")", "", 2289 ) 2290 items = append(items, p.row(node.FileFormat, data)) 2291 } 2292 2293 if node.Options != nil { 2294 items = append(items, p.row("WITH", p.Doc(&node.Options))) 2295 } 2296 return p.rlTable(items...) 2297 } 2298 2299 func (node *Export) doc(p *PrettyCfg) pretty.Doc { 2300 items := make([]pretty.TableRow, 0, 4) 2301 items = append(items, p.row("EXPORT", pretty.Nil)) 2302 items = append(items, p.row("INTO "+node.FileFormat, p.Doc(node.File))) 2303 if node.Options != nil { 2304 items = append(items, p.row("WITH", p.Doc(&node.Options))) 2305 } 2306 items = append(items, p.row("FROM", p.Doc(node.Query))) 2307 return p.rlTable(items...) 2308 } 2309 2310 func (node *NotExpr) doc(p *PrettyCfg) pretty.Doc { 2311 return p.nestUnder( 2312 pretty.Keyword("NOT"), 2313 p.exprDocWithParen(node.Expr), 2314 ) 2315 } 2316 2317 func (node *IsNullExpr) doc(p *PrettyCfg) pretty.Doc { 2318 return pretty.ConcatSpace( 2319 p.exprDocWithParen(node.Expr), 2320 pretty.Keyword("IS NULL"), 2321 ) 2322 } 2323 2324 func (node *IsNotNullExpr) doc(p *PrettyCfg) pretty.Doc { 2325 return pretty.ConcatSpace( 2326 p.exprDocWithParen(node.Expr), 2327 pretty.Keyword("IS NOT NULL"), 2328 ) 2329 } 2330 2331 func (node *CoalesceExpr) doc(p *PrettyCfg) pretty.Doc { 2332 return p.bracketKeyword( 2333 node.Name, "(", 2334 p.Doc(&node.Exprs), 2335 ")", "", 2336 ) 2337 } 2338 2339 func (node *AlterTable) doc(p *PrettyCfg) pretty.Doc { 2340 title := pretty.Keyword("ALTER TABLE") 2341 if node.IfExists { 2342 title = pretty.ConcatSpace(title, pretty.Keyword("IF EXISTS")) 2343 } 2344 title = pretty.ConcatSpace(title, p.Doc(node.Table)) 2345 return p.nestUnder( 2346 title, 2347 p.Doc(&node.Cmds), 2348 ) 2349 } 2350 2351 func (node *AlterTableCmds) doc(p *PrettyCfg) pretty.Doc { 2352 cmds := make([]pretty.Doc, len(*node)) 2353 for i, c := range *node { 2354 cmds[i] = p.Doc(c) 2355 } 2356 return p.commaSeparated(cmds...) 2357 } 2358 2359 func (node *AlterTableAddColumn) doc(p *PrettyCfg) pretty.Doc { 2360 title := pretty.Keyword("ADD COLUMN") 2361 if node.IfNotExists { 2362 title = pretty.ConcatSpace(title, pretty.Keyword("IF NOT EXISTS")) 2363 } 2364 return p.nestUnder( 2365 title, 2366 p.Doc(node.ColumnDef), 2367 ) 2368 } 2369 2370 func (node *Prepare) doc(p *PrettyCfg) pretty.Doc { 2371 return p.rlTable(node.docTable(p)...) 2372 } 2373 2374 func (node *Prepare) docTable(p *PrettyCfg) []pretty.TableRow { 2375 name := p.Doc(&node.Name) 2376 if len(node.Types) > 0 { 2377 typs := make([]pretty.Doc, len(node.Types)) 2378 for i, t := range node.Types { 2379 typs[i] = p.formatType(t) 2380 } 2381 name = pretty.ConcatSpace(name, 2382 p.bracket("(", p.commaSeparated(typs...), ")"), 2383 ) 2384 } 2385 return []pretty.TableRow{ 2386 p.row("PREPARE", name), 2387 p.row("AS", p.Doc(node.Statement)), 2388 } 2389 } 2390 2391 func (node *Execute) doc(p *PrettyCfg) pretty.Doc { 2392 return p.rlTable(node.docTable(p)...) 2393 } 2394 2395 func (node *Execute) docTable(p *PrettyCfg) []pretty.TableRow { 2396 name := p.Doc(&node.Name) 2397 if len(node.Params) > 0 { 2398 name = pretty.ConcatSpace( 2399 name, 2400 p.bracket("(", p.Doc(&node.Params), ")"), 2401 ) 2402 } 2403 rows := []pretty.TableRow{p.row("EXECUTE", name)} 2404 if node.DiscardRows { 2405 rows = append(rows, p.row("", pretty.Keyword("DISCARD ROWS"))) 2406 } 2407 return rows 2408 } 2409 2410 func (node *AnnotateTypeExpr) doc(p *PrettyCfg) pretty.Doc { 2411 if node.SyntaxMode == AnnotateShort { 2412 if typ, ok := GetStaticallyKnownType(node.Type); ok { 2413 switch typ.Family() { 2414 case types.JsonFamily: 2415 if sv, ok := node.Expr.(*StrVal); ok && p.JSONFmt { 2416 return p.jsonCast(sv, ":::", typ) 2417 } 2418 } 2419 } 2420 } 2421 return p.docAsString(node) 2422 } 2423 2424 func (node *DeclareCursor) docTable(p *PrettyCfg) []pretty.TableRow { 2425 optionsRow := pretty.Nil 2426 if node.Binary { 2427 optionsRow = pretty.ConcatSpace(optionsRow, pretty.Keyword("BINARY")) 2428 } 2429 if node.Sensitivity != UnspecifiedSensitivity { 2430 optionsRow = pretty.ConcatSpace(optionsRow, pretty.Keyword(node.Sensitivity.String())) 2431 } 2432 if node.Scroll != UnspecifiedScroll { 2433 optionsRow = pretty.ConcatSpace(optionsRow, pretty.Keyword(node.Scroll.String())) 2434 } 2435 cursorRow := pretty.Nil 2436 if node.Hold { 2437 cursorRow = pretty.ConcatSpace(cursorRow, pretty.Keyword("WITH HOLD")) 2438 } 2439 return []pretty.TableRow{ 2440 p.row("DECLARE", pretty.ConcatLine(p.Doc(&node.Name), optionsRow)), 2441 p.row("CURSOR", cursorRow), 2442 p.row("FOR", node.Select.doc(p)), 2443 } 2444 } 2445 2446 func (node *DeclareCursor) doc(p *PrettyCfg) pretty.Doc { 2447 return p.rlTable(node.docTable(p)...) 2448 } 2449 2450 func (node *CursorStmt) doc(p *PrettyCfg) pretty.Doc { 2451 ret := pretty.Nil 2452 fetchType := node.FetchType.String() 2453 if fetchType != "" { 2454 ret = pretty.ConcatSpace(ret, pretty.Keyword(fetchType)) 2455 } 2456 if node.FetchType.HasCount() { 2457 ret = pretty.ConcatSpace(ret, pretty.Text(strconv.Itoa(int(node.Count)))) 2458 } 2459 return pretty.Fold(pretty.ConcatSpace, 2460 ret, 2461 pretty.Keyword("FROM"), 2462 p.Doc(&node.Name), 2463 ) 2464 } 2465 2466 func (node *FetchCursor) doc(p *PrettyCfg) pretty.Doc { 2467 return pretty.ConcatSpace(pretty.Keyword("FETCH"), node.CursorStmt.doc(p)) 2468 } 2469 2470 func (node *MoveCursor) doc(p *PrettyCfg) pretty.Doc { 2471 return pretty.ConcatSpace(pretty.Keyword("MOVE"), node.CursorStmt.doc(p)) 2472 } 2473 2474 func (node *CloseCursor) doc(p *PrettyCfg) pretty.Doc { 2475 close := pretty.Keyword("CLOSE") 2476 if node.All { 2477 return pretty.ConcatSpace(close, pretty.Keyword("ALL")) 2478 } 2479 return pretty.ConcatSpace(close, p.Doc(&node.Name)) 2480 } 2481 2482 // jsonCast attempts to pretty print a string that is cast or asserted as JSON. 2483 func (p *PrettyCfg) jsonCast(sv *StrVal, op string, typ *types.T) pretty.Doc { 2484 return pretty.Fold(pretty.Concat, 2485 p.jsonString(sv.RawString()), 2486 pretty.Text(op), 2487 p.formatType(typ), 2488 ) 2489 } 2490 2491 // jsonString parses s as JSON and pretty prints it. 2492 func (p *PrettyCfg) jsonString(s string) pretty.Doc { 2493 j, err := json.ParseJSON(s) 2494 if err != nil { 2495 return pretty.Text(s) 2496 } 2497 return p.bracket(`'`, p.jsonNode(j), `'`) 2498 } 2499 2500 // jsonNode pretty prints a JSON node. 2501 func (p *PrettyCfg) jsonNode(j json.JSON) pretty.Doc { 2502 // Figure out what type this is. 2503 if it, _ := j.ObjectIter(); it != nil { 2504 // Object. 2505 elems := make([]pretty.Doc, 0, j.Len()) 2506 for it.Next() { 2507 elems = append(elems, p.nestUnder( 2508 pretty.Concat( 2509 pretty.Text(json.FromString(it.Key()).String()), 2510 pretty.Text(`:`), 2511 ), 2512 p.jsonNode(it.Value()), 2513 )) 2514 } 2515 return p.bracket("{", p.commaSeparated(elems...), "}") 2516 } else if n := j.Len(); n > 0 { 2517 // Non-empty array. 2518 elems := make([]pretty.Doc, n) 2519 for i := 0; i < n; i++ { 2520 elem, err := j.FetchValIdx(i) 2521 if err != nil { 2522 return pretty.Text(j.String()) 2523 } 2524 elems[i] = p.jsonNode(elem) 2525 } 2526 return p.bracket("[", p.commaSeparated(elems...), "]") 2527 } 2528 // Other. 2529 return pretty.Text(j.String()) 2530 }