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) {}