github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/testutils/reduce/reducesql/reducesql.go (about) 1 // Copyright 2019 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 reducesql 12 13 import ( 14 "bytes" 15 "fmt" 16 "go/constant" 17 "regexp" 18 "strings" 19 20 "github.com/cockroachdb/cockroach/pkg/sql/parser" 21 // Import builtins. 22 _ "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins" 23 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 24 "github.com/cockroachdb/cockroach/pkg/testutils/reduce" 25 ) 26 27 // SQLPasses is a collection of reduce.Pass interfaces that reduce SQL 28 // statements. 29 var SQLPasses = []reduce.Pass{ 30 removeStatement, 31 replaceStmt, 32 removeWithCTEs, 33 removeWith, 34 removeCreateDefs, 35 removeValuesCols, 36 removeWithSelectExprs, 37 removeSelectAsExprs, 38 removeValuesRows, 39 removeSelectExprs, 40 nullExprs, 41 nullifyFuncArgs, 42 removeLimit, 43 removeOrderBy, 44 removeOrderByExprs, 45 removeGroupBy, 46 removeGroupByExprs, 47 removeCreateNullDefs, 48 removeIndexCols, 49 removeWindowPartitions, 50 removeDBSchema, 51 removeFroms, 52 removeJoins, 53 removeWhere, 54 removeHaving, 55 removeDistinct, 56 simplifyOnCond, 57 simplifyVal, 58 removeCTENames, 59 removeCasts, 60 removeAliases, 61 unparenthesize, 62 } 63 64 type sqlWalker struct { 65 topOnly bool 66 match func(int, interface{}) int 67 replace func(int, interface{}) (int, tree.NodeFormatter) 68 } 69 70 // walkSQL walks SQL statements and allows for in-place transformations to be 71 // made directly to the nodes. match is a function that does both matching 72 // and transformation. It takes an int specifying the 0-based occurrence to 73 // transform. If the number of possible transformations is lower than that, 74 // nothing is mutated. It returns the number of transformations it could have 75 // performed. It is safe to mutate AST nodes directly because the string is 76 // reparsed into a new AST each time. 77 func walkSQL(name string, match func(transform int, node interface{}) (matched int)) reduce.Pass { 78 w := sqlWalker{ 79 match: match, 80 } 81 return reduce.MakeIntPass(name, w.Transform) 82 } 83 84 // replaceStatement is like walkSQL, except if it returns a non-nil 85 // replacement, the top-level SQL statement is completely replaced with the 86 // return value. 87 func replaceStatement( 88 name string, 89 replace func(transform int, node interface{}) (matched int, replacement tree.NodeFormatter), 90 ) reduce.Pass { 91 w := sqlWalker{ 92 replace: replace, 93 } 94 return reduce.MakeIntPass(name, w.Transform) 95 } 96 97 // replaceTopStatement is like replaceStatement but only applies to top-level 98 // statements. 99 func replaceTopStatement( 100 name string, 101 replace func(transform int, node interface{}) (matched int, replacement tree.NodeFormatter), 102 ) reduce.Pass { 103 w := sqlWalker{ 104 replace: replace, 105 topOnly: true, 106 } 107 return reduce.MakeIntPass(name, w.Transform) 108 } 109 110 var ( 111 // LogUnknown determines whether unknown types encountered during 112 // statement walking. 113 LogUnknown bool 114 unknownTypes = map[string]bool{} 115 ) 116 117 func (w sqlWalker) Transform(s string, i int) (out string, ok bool, err error) { 118 stmts, err := parser.Parse(s) 119 if err != nil { 120 return "", false, err 121 } 122 123 asts := make([]tree.NodeFormatter, len(stmts)) 124 for si, stmt := range stmts { 125 asts[si] = stmt.AST 126 } 127 128 var replacement tree.NodeFormatter 129 // nodeCount is incremented on each visited node per statement. It is 130 // currently used to determine if walk is at the top-level statement 131 // or not. 132 var nodeCount int 133 var walk func(...interface{}) 134 walk = func(nodes ...interface{}) { 135 for _, node := range nodes { 136 nodeCount++ 137 if w.topOnly && nodeCount > 1 { 138 return 139 } 140 if i < 0 { 141 return 142 } 143 var matches int 144 if w.match != nil { 145 matches = w.match(i, node) 146 } else { 147 matches, replacement = w.replace(i, node) 148 } 149 i -= matches 150 151 if node == nil { 152 continue 153 } 154 if _, ok := node.(tree.Datum); ok { 155 continue 156 } 157 158 switch node := node.(type) { 159 case *tree.AliasedTableExpr: 160 walk(node.Expr) 161 case *tree.AndExpr: 162 walk(node.Left, node.Right) 163 case *tree.AnnotateTypeExpr: 164 walk(node.Expr) 165 case *tree.Array: 166 walk(node.Exprs) 167 case *tree.BinaryExpr: 168 walk(node.Left, node.Right) 169 case *tree.CaseExpr: 170 walk(node.Expr, node.Else) 171 for _, w := range node.Whens { 172 walk(w.Cond, w.Val) 173 } 174 case *tree.CastExpr: 175 walk(node.Expr) 176 case *tree.CoalesceExpr: 177 for _, expr := range node.Exprs { 178 walk(expr) 179 } 180 case *tree.ColumnTableDef: 181 case *tree.ComparisonExpr: 182 walk(node.Left, node.Right) 183 case *tree.CreateTable: 184 for _, def := range node.Defs { 185 walk(def) 186 } 187 if node.AsSource != nil { 188 walk(node.AsSource) 189 } 190 case *tree.CTE: 191 walk(node.Stmt) 192 case *tree.DBool: 193 case tree.Exprs: 194 for _, expr := range node { 195 walk(expr) 196 } 197 case *tree.FamilyTableDef: 198 case *tree.FuncExpr: 199 if node.WindowDef != nil { 200 walk(node.WindowDef) 201 } 202 walk(node.Exprs, node.Filter) 203 case *tree.IndexTableDef: 204 case *tree.JoinTableExpr: 205 walk(node.Left, node.Right, node.Cond) 206 case *tree.NotExpr: 207 walk(node.Expr) 208 case *tree.NumVal: 209 case *tree.OnJoinCond: 210 walk(node.Expr) 211 case *tree.OrExpr: 212 walk(node.Left, node.Right) 213 case *tree.ParenExpr: 214 walk(node.Expr) 215 case *tree.ParenSelect: 216 walk(node.Select) 217 case *tree.RowsFromExpr: 218 for _, expr := range node.Items { 219 walk(expr) 220 } 221 case *tree.Select: 222 if node.With != nil { 223 walk(node.With) 224 } 225 walk(node.Select) 226 case *tree.SelectClause: 227 walk(node.Exprs) 228 if node.Where != nil { 229 walk(node.Where) 230 } 231 if node.Having != nil { 232 walk(node.Having) 233 } 234 for _, table := range node.From.Tables { 235 walk(table) 236 } 237 case tree.SelectExpr: 238 walk(node.Expr) 239 case tree.SelectExprs: 240 for _, expr := range node { 241 walk(expr) 242 } 243 case *tree.SetVar: 244 for _, expr := range node.Values { 245 walk(expr) 246 } 247 case *tree.StrVal: 248 case *tree.Subquery: 249 walk(node.Select) 250 case *tree.TableName: 251 case *tree.Tuple: 252 for _, expr := range node.Exprs { 253 walk(expr) 254 } 255 case *tree.UnaryExpr: 256 walk(node.Expr) 257 case *tree.UniqueConstraintTableDef: 258 case *tree.UnionClause: 259 walk(node.Left, node.Right) 260 case tree.UnqualifiedStar: 261 case *tree.UnresolvedName: 262 case *tree.ValuesClause: 263 for _, row := range node.Rows { 264 walk(row) 265 } 266 case *tree.Where: 267 walk(node.Expr) 268 case *tree.WindowDef: 269 walk(node.Partitions) 270 if node.Frame != nil { 271 walk(node.Frame) 272 } 273 case *tree.WindowFrame: 274 if node.Bounds.StartBound != nil { 275 walk(node.Bounds.StartBound) 276 } 277 if node.Bounds.EndBound != nil { 278 walk(node.Bounds.EndBound) 279 } 280 case *tree.WindowFrameBound: 281 walk(node.OffsetExpr) 282 case *tree.Window: 283 case *tree.With: 284 for _, expr := range node.CTEList { 285 walk(expr) 286 } 287 default: 288 if LogUnknown { 289 n := fmt.Sprintf("%T", node) 290 if !unknownTypes[n] { 291 unknownTypes[n] = true 292 fmt.Println("UNKNOWN", n) 293 } 294 } 295 } 296 } 297 } 298 299 for i, ast := range asts { 300 replacement = nil 301 nodeCount = 0 302 walk(ast) 303 if replacement != nil { 304 asts[i] = replacement 305 } 306 } 307 if i >= 0 { 308 // Didn't find enough matches, so we're done. 309 return s, false, nil 310 } 311 var sb strings.Builder 312 for i, ast := range asts { 313 if i > 0 { 314 sb.WriteString("\n\n") 315 } 316 sb.WriteString(tree.Pretty(ast)) 317 sb.WriteString(";") 318 } 319 return sb.String(), true, nil 320 } 321 322 // Pretty formats input SQL into a standard format. Input SQL should be run 323 // through this before reducing so file size comparisons are useful. 324 func Pretty(s []byte) ([]byte, error) { 325 stmts, err := parser.Parse(string(s)) 326 if err != nil { 327 return nil, err 328 } 329 330 var sb bytes.Buffer 331 for i, stmt := range stmts { 332 if i > 0 { 333 sb.WriteString("\n\n") 334 } 335 sb.WriteString(tree.Pretty(stmt.AST)) 336 sb.WriteString(";") 337 } 338 return sb.Bytes(), nil 339 } 340 341 var ( 342 // Mutations. 343 344 removeLimit = walkSQL("remove LIMIT", func(xfi int, node interface{}) int { 345 xf := xfi == 0 346 switch node := node.(type) { 347 case *tree.Delete: 348 if node.Limit != nil { 349 if xf { 350 node.Limit = nil 351 } 352 return 1 353 } 354 case *tree.Select: 355 if node.Limit != nil { 356 if xf { 357 node.Limit = nil 358 } 359 return 1 360 } 361 case *tree.Update: 362 if node.Limit != nil { 363 if xf { 364 node.Limit = nil 365 } 366 return 1 367 } 368 } 369 return 0 370 }) 371 removeOrderBy = walkSQL("remove ORDER BY", func(xfi int, node interface{}) int { 372 xf := xfi == 0 373 switch node := node.(type) { 374 case *tree.Delete: 375 if node.OrderBy != nil { 376 if xf { 377 node.OrderBy = nil 378 } 379 return 1 380 } 381 case *tree.FuncExpr: 382 if node.OrderBy != nil { 383 if xf { 384 node.OrderBy = nil 385 } 386 return 1 387 } 388 case *tree.Select: 389 if node.OrderBy != nil { 390 if xf { 391 node.OrderBy = nil 392 } 393 return 1 394 } 395 case *tree.Update: 396 if node.OrderBy != nil { 397 if xf { 398 node.OrderBy = nil 399 } 400 return 1 401 } 402 case *tree.WindowDef: 403 if node.OrderBy != nil { 404 if xf { 405 node.OrderBy = nil 406 } 407 return 1 408 } 409 } 410 return 0 411 }) 412 removeOrderByExprs = walkSQL("remove ORDER BY exprs", func(xfi int, node interface{}) int { 413 switch node := node.(type) { 414 case *tree.Delete: 415 n := len(node.OrderBy) 416 if xfi < len(node.OrderBy) { 417 node.OrderBy = append(node.OrderBy[:xfi], node.OrderBy[xfi+1:]...) 418 } 419 return n 420 case *tree.FuncExpr: 421 n := len(node.OrderBy) 422 if xfi < len(node.OrderBy) { 423 node.OrderBy = append(node.OrderBy[:xfi], node.OrderBy[xfi+1:]...) 424 } 425 return n 426 case *tree.Select: 427 n := len(node.OrderBy) 428 if xfi < len(node.OrderBy) { 429 node.OrderBy = append(node.OrderBy[:xfi], node.OrderBy[xfi+1:]...) 430 } 431 return n 432 case *tree.Update: 433 n := len(node.OrderBy) 434 if xfi < len(node.OrderBy) { 435 node.OrderBy = append(node.OrderBy[:xfi], node.OrderBy[xfi+1:]...) 436 } 437 return n 438 case *tree.WindowDef: 439 n := len(node.OrderBy) 440 if xfi < len(node.OrderBy) { 441 node.OrderBy = append(node.OrderBy[:xfi], node.OrderBy[xfi+1:]...) 442 } 443 return n 444 } 445 return 0 446 }) 447 removeGroupBy = walkSQL("remove GROUP BY", func(xfi int, node interface{}) int { 448 xf := xfi == 0 449 switch node := node.(type) { 450 case *tree.SelectClause: 451 if node.GroupBy != nil { 452 if xf { 453 node.GroupBy = nil 454 } 455 return 1 456 } 457 } 458 return 0 459 }) 460 removeGroupByExprs = walkSQL("remove GROUP BY exprs", func(xfi int, node interface{}) int { 461 switch node := node.(type) { 462 case *tree.SelectClause: 463 n := len(node.GroupBy) 464 if xfi < len(node.GroupBy) { 465 node.GroupBy = append(node.GroupBy[:xfi], node.GroupBy[xfi+1:]...) 466 } 467 return n 468 } 469 return 0 470 }) 471 nullExprs = walkSQL("nullify SELECT exprs", func(xfi int, node interface{}) int { 472 xf := xfi == 0 473 switch node := node.(type) { 474 case *tree.SelectClause: 475 if len(node.Exprs) != 1 || node.Exprs[0].Expr != tree.DNull { 476 if xf { 477 node.Exprs = tree.SelectExprs{tree.SelectExpr{Expr: tree.DNull}} 478 } 479 return 1 480 } 481 } 482 return 0 483 }) 484 removeSelectExprs = walkSQL("remove SELECT exprs", func(xfi int, node interface{}) int { 485 switch node := node.(type) { 486 case *tree.SelectClause: 487 n := len(node.Exprs) 488 if xfi < len(node.Exprs) { 489 node.Exprs = append(node.Exprs[:xfi], node.Exprs[xfi+1:]...) 490 } 491 return n 492 } 493 return 0 494 }) 495 removeWithSelectExprs = walkSQL("remove WITH SELECT exprs", func(xfi int, node interface{}) int { 496 switch node := node.(type) { 497 case *tree.CTE: 498 if len(node.Name.Cols) < 1 { 499 break 500 } 501 slct, ok := node.Stmt.(*tree.Select) 502 if !ok { 503 break 504 } 505 clause, ok := slct.Select.(*tree.SelectClause) 506 if !ok { 507 break 508 } 509 n := len(clause.Exprs) 510 if xfi < len(clause.Exprs) { 511 node.Name.Cols = append(node.Name.Cols[:xfi], node.Name.Cols[xfi+1:]...) 512 clause.Exprs = append(clause.Exprs[:xfi], clause.Exprs[xfi+1:]...) 513 } 514 return n 515 } 516 return 0 517 }) 518 removeValuesCols = walkSQL("remove VALUES cols", func(xfi int, node interface{}) int { 519 switch node := node.(type) { 520 case *tree.AliasedTableExpr: 521 subq, ok := node.Expr.(*tree.Subquery) 522 if !ok { 523 break 524 } 525 values, ok := skipParenSelect(subq.Select).(*tree.ValuesClause) 526 if !ok { 527 break 528 } 529 if len(values.Rows) < 1 { 530 break 531 } 532 n := len(values.Rows[0]) 533 if xfi < n { 534 removeValuesCol(values, xfi) 535 // Remove the VALUES alias. 536 if len(node.As.Cols) > xfi { 537 node.As.Cols = append(node.As.Cols[:xfi], node.As.Cols[xfi+1:]...) 538 } 539 } 540 return n 541 case *tree.CTE: 542 slct, ok := node.Stmt.(*tree.Select) 543 if !ok { 544 break 545 } 546 clause, ok := slct.Select.(*tree.SelectClause) 547 if !ok { 548 break 549 } 550 if len(clause.From.Tables) != 1 { 551 break 552 } 553 ate, ok := clause.From.Tables[0].(*tree.AliasedTableExpr) 554 if !ok { 555 break 556 } 557 subq, ok := ate.Expr.(*tree.Subquery) 558 if !ok { 559 break 560 } 561 values, ok := skipParenSelect(subq.Select).(*tree.ValuesClause) 562 if !ok { 563 break 564 } 565 if len(values.Rows) < 1 { 566 break 567 } 568 n := len(values.Rows[0]) 569 if xfi < n { 570 removeValuesCol(values, xfi) 571 // Remove the WITH alias. 572 if len(node.Name.Cols) > xfi { 573 node.Name.Cols = append(node.Name.Cols[:xfi], node.Name.Cols[xfi+1:]...) 574 } 575 // Remove the VALUES alias. 576 if len(ate.As.Cols) > xfi { 577 ate.As.Cols = append(ate.As.Cols[:xfi], ate.As.Cols[xfi+1:]...) 578 } 579 } 580 return n 581 case *tree.ValuesClause: 582 if len(node.Rows) < 1 { 583 break 584 } 585 n := len(node.Rows[0]) 586 if xfi < n { 587 removeValuesCol(node, xfi) 588 } 589 return n 590 } 591 return 0 592 }) 593 removeSelectAsExprs = walkSQL("remove SELECT AS exprs", func(xfi int, node interface{}) int { 594 switch node := node.(type) { 595 case *tree.AliasedTableExpr: 596 if len(node.As.Cols) < 1 { 597 break 598 } 599 subq, ok := node.Expr.(*tree.Subquery) 600 if !ok { 601 break 602 } 603 clause, ok := skipParenSelect(subq.Select).(*tree.SelectClause) 604 if !ok { 605 break 606 } 607 n := len(clause.Exprs) 608 if xfi < len(clause.Exprs) { 609 node.As.Cols = append(node.As.Cols[:xfi], node.As.Cols[xfi+1:]...) 610 clause.Exprs = append(clause.Exprs[:xfi], clause.Exprs[xfi+1:]...) 611 } 612 return n 613 } 614 return 0 615 }) 616 removeWith = walkSQL("remove WITH", func(xfi int, node interface{}) int { 617 xf := xfi == 0 618 switch node := node.(type) { 619 case *tree.Delete: 620 if node.With != nil { 621 if xf { 622 node.With = nil 623 } 624 return 1 625 } 626 case *tree.Insert: 627 if node.With != nil { 628 if xf { 629 node.With = nil 630 } 631 return 1 632 } 633 case *tree.Select: 634 if node.With != nil { 635 if xf { 636 node.With = nil 637 } 638 return 1 639 } 640 case *tree.Update: 641 if node.With != nil { 642 if xf { 643 node.With = nil 644 } 645 return 1 646 } 647 } 648 return 0 649 }) 650 removeCreateDefs = walkSQL("remove CREATE defs", func(xfi int, node interface{}) int { 651 switch node := node.(type) { 652 case *tree.CreateTable: 653 n := len(node.Defs) 654 if xfi < len(node.Defs) { 655 node.Defs = append(node.Defs[:xfi], node.Defs[xfi+1:]...) 656 } 657 return n 658 } 659 return 0 660 }) 661 removeCreateNullDefs = walkSQL("remove CREATE NULL defs", func(xfi int, node interface{}) int { 662 xf := xfi == 0 663 switch node := node.(type) { 664 case *tree.ColumnTableDef: 665 if node.Nullable.Nullability != tree.SilentNull { 666 if xf { 667 node.Nullable.Nullability = tree.SilentNull 668 } 669 return 1 670 } 671 } 672 return 0 673 }) 674 removeIndexCols = walkSQL("remove INDEX cols", func(xfi int, node interface{}) int { 675 removeCol := func(idx *tree.IndexTableDef) int { 676 n := len(idx.Columns) 677 if xfi < len(idx.Columns) { 678 idx.Columns = append(idx.Columns[:xfi], idx.Columns[xfi+1:]...) 679 } 680 return n 681 } 682 switch node := node.(type) { 683 case *tree.IndexTableDef: 684 return removeCol(node) 685 case *tree.UniqueConstraintTableDef: 686 return removeCol(&node.IndexTableDef) 687 } 688 return 0 689 }) 690 removeWindowPartitions = walkSQL("remove WINDOW partitions", func(xfi int, node interface{}) int { 691 switch node := node.(type) { 692 case *tree.WindowDef: 693 n := len(node.Partitions) 694 if xfi < len(node.Partitions) { 695 node.Partitions = append(node.Partitions[:xfi], node.Partitions[xfi+1:]...) 696 } 697 return n 698 } 699 return 0 700 }) 701 removeValuesRows = walkSQL("remove VALUES rows", func(xfi int, node interface{}) int { 702 switch node := node.(type) { 703 case *tree.ValuesClause: 704 n := len(node.Rows) 705 if xfi < len(node.Rows) { 706 node.Rows = append(node.Rows[:xfi], node.Rows[xfi+1:]...) 707 } 708 return n 709 } 710 return 0 711 }) 712 removeWithCTEs = walkSQL("remove WITH CTEs", func(xfi int, node interface{}) int { 713 switch node := node.(type) { 714 case *tree.With: 715 n := len(node.CTEList) 716 if xfi < len(node.CTEList) { 717 node.CTEList = append(node.CTEList[:xfi], node.CTEList[xfi+1:]...) 718 } 719 return n 720 } 721 return 0 722 }) 723 removeCTENames = walkSQL("remove CTE names", func(xfi int, node interface{}) int { 724 xf := xfi == 0 725 switch node := node.(type) { 726 case *tree.CTE: 727 if len(node.Name.Cols) > 0 { 728 if xf { 729 node.Name.Cols = nil 730 } 731 return 1 732 } 733 } 734 return 0 735 }) 736 removeFroms = walkSQL("remove FROMs", func(xfi int, node interface{}) int { 737 switch node := node.(type) { 738 case *tree.SelectClause: 739 n := len(node.From.Tables) 740 if xfi < len(node.From.Tables) { 741 node.From.Tables = append(node.From.Tables[:xfi], node.From.Tables[xfi+1:]...) 742 } 743 return n 744 } 745 return 0 746 }) 747 removeJoins = walkSQL("remove JOINs", func(xfi int, node interface{}) int { 748 // Remove JOINs. Replace them with either the left or right 749 // side based on if xfi is even or odd. 750 switch node := node.(type) { 751 case *tree.SelectClause: 752 idx := xfi / 2 753 n := 0 754 for i, t := range node.From.Tables { 755 switch t := t.(type) { 756 case *tree.JoinTableExpr: 757 if n == idx { 758 if xfi%2 == 0 { 759 node.From.Tables[i] = t.Left 760 } else { 761 node.From.Tables[i] = t.Right 762 } 763 } 764 n += 2 765 } 766 } 767 return n 768 } 769 return 0 770 }) 771 simplifyVal = walkSQL("simplify vals", func(xfi int, node interface{}) int { 772 xf := xfi == 0 773 switch node := node.(type) { 774 case *tree.StrVal: 775 if node.RawString() != "" { 776 if xf { 777 *node = *tree.NewStrVal("") 778 } 779 return 1 780 } 781 case *tree.NumVal: 782 if node.OrigString() != "0" { 783 if xf { 784 *node = *tree.NewNumVal(constant.MakeInt64(0), "0", false /* negative */) 785 } 786 return 1 787 } 788 } 789 return 0 790 }) 791 removeWhere = walkSQL("remove WHERE", func(xfi int, node interface{}) int { 792 xf := xfi == 0 793 switch node := node.(type) { 794 case *tree.SelectClause: 795 if node.Where != nil { 796 if xf { 797 node.Where = nil 798 } 799 return 1 800 } 801 } 802 return 0 803 }) 804 removeHaving = walkSQL("remove HAVING", func(xfi int, node interface{}) int { 805 xf := xfi == 0 806 switch node := node.(type) { 807 case *tree.SelectClause: 808 if node.Having != nil { 809 if xf { 810 node.Having = nil 811 } 812 return 1 813 } 814 } 815 return 0 816 }) 817 removeDistinct = walkSQL("remove DISTINCT", func(xfi int, node interface{}) int { 818 xf := xfi == 0 819 switch node := node.(type) { 820 case *tree.SelectClause: 821 if node.Distinct { 822 if xf { 823 node.Distinct = false 824 } 825 return 1 826 } 827 } 828 return 0 829 }) 830 unparenthesize = walkSQL("unparenthesize", func(xfi int, node interface{}) int { 831 switch node := node.(type) { 832 case tree.Exprs: 833 n := 0 834 for i, x := range node { 835 if x, ok := x.(*tree.ParenExpr); ok { 836 if n == xfi { 837 node[i] = x.Expr 838 } 839 n++ 840 } 841 } 842 return n 843 } 844 return 0 845 }) 846 nullifyFuncArgs = walkSQL("nullify function args", func(xfi int, node interface{}) int { 847 switch node := node.(type) { 848 case *tree.FuncExpr: 849 n := 0 850 for i, x := range node.Exprs { 851 if x != tree.DNull { 852 if n == xfi { 853 node.Exprs[i] = tree.DNull 854 } 855 n++ 856 } 857 } 858 return n 859 } 860 return 0 861 }) 862 simplifyOnCond = walkSQL("simplify ON conditions", func(xfi int, node interface{}) int { 863 xf := xfi == 0 864 switch node := node.(type) { 865 case *tree.OnJoinCond: 866 if node.Expr != tree.DBoolTrue { 867 if xf { 868 node.Expr = tree.DBoolTrue 869 } 870 return 1 871 } 872 } 873 return 0 874 }) 875 876 // Replacements. 877 878 removeStatement = replaceTopStatement("remove statements", func(xfi int, node interface{}) (int, tree.NodeFormatter) { 879 xf := xfi == 0 880 if _, ok := node.(tree.Statement); ok { 881 if xf { 882 return 1, emptyStatement{} 883 } 884 return 1, nil 885 } 886 return 0, nil 887 }) 888 replaceStmt = replaceStatement("replace statements", func(xfi int, node interface{}) (int, tree.NodeFormatter) { 889 xf := xfi == 0 890 switch node := node.(type) { 891 case *tree.ParenSelect: 892 if xf { 893 return 1, node.Select 894 } 895 return 1, nil 896 case *tree.Subquery: 897 if xf { 898 return 1, node.Select 899 } 900 return 1, nil 901 case *tree.With: 902 n := len(node.CTEList) 903 if xfi < len(node.CTEList) { 904 return n, node.CTEList[xfi].Stmt 905 } 906 return n, nil 907 } 908 return 0, nil 909 }) 910 911 // Regexes. 912 913 removeCastsRE = regexp.MustCompile(`:::?[a-zA-Z0-9]+`) 914 removeCasts = reduce.MakeIntPass("remove casts", func(s string, i int) (string, bool, error) { 915 out := removeCastsRE.ReplaceAllStringFunc(s, func(found string) string { 916 i-- 917 if i == -1 { 918 return "" 919 } 920 return found 921 }) 922 return out, i < 0, nil 923 }) 924 removeAliasesRE = regexp.MustCompile(`\sAS\s+\w+`) 925 removeAliases = reduce.MakeIntPass("remove aliases", func(s string, i int) (string, bool, error) { 926 out := removeAliasesRE.ReplaceAllStringFunc(s, func(found string) string { 927 i-- 928 if i == -1 { 929 return "" 930 } 931 return found 932 }) 933 return out, i < 0, nil 934 }) 935 removeDBSchemaRE = regexp.MustCompile(`\w+\.\w+\.`) 936 removeDBSchema = reduce.MakeIntPass("remove DB schema", func(s string, i int) (string, bool, error) { 937 // Remove the database and schema from "default.public.xxx". 938 out := removeDBSchemaRE.ReplaceAllStringFunc(s, func(found string) string { 939 i-- 940 if i == -1 { 941 return "" 942 } 943 return found 944 }) 945 return out, i < 0, nil 946 }) 947 ) 948 949 func skipParenSelect(stmt tree.SelectStatement) tree.SelectStatement { 950 for { 951 ps, ok := stmt.(*tree.ParenSelect) 952 if !ok { 953 return stmt 954 } 955 stmt = ps.Select.Select 956 } 957 958 } 959 960 func removeValuesCol(values *tree.ValuesClause, col int) { 961 for i, row := range values.Rows { 962 values.Rows[i] = append(row[:col], row[col+1:]...) 963 } 964 } 965 966 type emptyStatement struct{} 967 968 func (e emptyStatement) Format(*tree.FmtCtx) {}