github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/mutations/mutations.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 mutations
    12  
    13  import (
    14  	"bytes"
    15  	"encoding/json"
    16  	"math/rand"
    17  	"regexp"
    18  	"sort"
    19  	"strings"
    20  
    21  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/stats"
    25  	"github.com/cockroachdb/cockroach/pkg/util/encoding"
    26  )
    27  
    28  var (
    29  	// StatisticsMutator adds ALTER TABLE INJECT STATISTICS statements.
    30  	StatisticsMutator MultiStatementMutation = statisticsMutator
    31  
    32  	// ForeignKeyMutator adds ALTER TABLE ADD FOREIGN KEY statements.
    33  	ForeignKeyMutator MultiStatementMutation = foreignKeyMutator
    34  
    35  	// ColumnFamilyMutator modifies a CREATE TABLE statement without any FAMILY
    36  	// definitions to have random FAMILY definitions.
    37  	ColumnFamilyMutator StatementMutator = sqlbase.ColumnFamilyMutator
    38  
    39  	// IndexStoringMutator modifies the STORING clause of CREATE INDEX and
    40  	// indexes in CREATE TABLE.
    41  	IndexStoringMutator MultiStatementMutation = sqlbase.IndexStoringMutator
    42  
    43  	// PostgresMutator modifies strings such that they execute identically
    44  	// in both Postgres and Cockroach (however this mutator does not remove
    45  	// features not supported by Postgres; use PostgresCreateTableMutator
    46  	// for those).
    47  	PostgresMutator StatementStringMutator = postgresMutator
    48  
    49  	// PostgresCreateTableMutator modifies CREATE TABLE statements to
    50  	// remove any features not supported by Postgres that would change
    51  	// results (like descending primary keys). This should be used on the
    52  	// output of sqlbase.RandCreateTable.
    53  	PostgresCreateTableMutator MultiStatementMutation = postgresCreateTableMutator
    54  )
    55  
    56  var (
    57  	// These are used in pkg/compose/compare/compare/compare_test.go, but
    58  	// it has a build tag so it's not detected by the linter.
    59  	_ = IndexStoringMutator
    60  	_ = PostgresCreateTableMutator
    61  )
    62  
    63  // StatementMutator defines a func that can change a statement.
    64  type StatementMutator func(rng *rand.Rand, stmt tree.Statement) (changed bool)
    65  
    66  // MultiStatementMutation defines a func that can return a list of new and/or mutated statements.
    67  type MultiStatementMutation func(rng *rand.Rand, stmts []tree.Statement) (mutated []tree.Statement, changed bool)
    68  
    69  // Mutate implements the Mutator interface.
    70  func (sm StatementMutator) Mutate(
    71  	rng *rand.Rand, stmts []tree.Statement,
    72  ) (mutated []tree.Statement, changed bool) {
    73  	for _, stmt := range stmts {
    74  		sc := sm(rng, stmt)
    75  		changed = changed || sc
    76  	}
    77  	return stmts, changed
    78  }
    79  
    80  // Mutate implements the Mutator interface.
    81  func (msm MultiStatementMutation) Mutate(
    82  	rng *rand.Rand, stmts []tree.Statement,
    83  ) (mutated []tree.Statement, changed bool) {
    84  	return msm(rng, stmts)
    85  }
    86  
    87  // Apply executes all mutators on stmts. It returns the (possibly mutated and
    88  // changed in place) statements and a boolean indicating whether any changes
    89  // were made.
    90  func Apply(
    91  	rng *rand.Rand, stmts []tree.Statement, mutators ...sqlbase.Mutator,
    92  ) (mutated []tree.Statement, changed bool) {
    93  	var mc bool
    94  	for _, m := range mutators {
    95  		stmts, mc = m.Mutate(rng, stmts)
    96  		changed = changed || mc
    97  	}
    98  	return stmts, changed
    99  }
   100  
   101  // StringMutator defines a mutator that works on strings.
   102  type StringMutator interface {
   103  	MutateString(*rand.Rand, string) (mutated string, changed bool)
   104  }
   105  
   106  // StatementStringMutator defines a func that mutates a string.
   107  type StatementStringMutator func(*rand.Rand, string) string
   108  
   109  // Mutate implements the Mutator interface.
   110  func (sm StatementStringMutator) Mutate(
   111  	rng *rand.Rand, stmts []tree.Statement,
   112  ) (mutated []tree.Statement, changed bool) {
   113  	panic("can only be used with MutateString")
   114  }
   115  
   116  // MutateString implements the StringMutator interface.
   117  func (sm StatementStringMutator) MutateString(
   118  	rng *rand.Rand, q string,
   119  ) (mutated string, changed bool) {
   120  	newq := sm(rng, q)
   121  	return newq, newq != q
   122  }
   123  
   124  // ApplyString executes all mutators on input. A mutator can also be a
   125  // StringMutator which will operate after all other mutators.
   126  func ApplyString(
   127  	rng *rand.Rand, input string, mutators ...sqlbase.Mutator,
   128  ) (output string, changed bool) {
   129  	parsed, err := parser.Parse(input)
   130  	if err != nil {
   131  		return input, false
   132  	}
   133  
   134  	stmts := make([]tree.Statement, len(parsed))
   135  	for i, p := range parsed {
   136  		stmts[i] = p.AST
   137  	}
   138  
   139  	var normalMutators []sqlbase.Mutator
   140  	var stringMutators []StringMutator
   141  	for _, m := range mutators {
   142  		if sm, ok := m.(StringMutator); ok {
   143  			stringMutators = append(stringMutators, sm)
   144  		} else {
   145  			normalMutators = append(normalMutators, m)
   146  		}
   147  	}
   148  	stmts, changed = Apply(rng, stmts, normalMutators...)
   149  	if changed {
   150  		var sb strings.Builder
   151  		for _, s := range stmts {
   152  			sb.WriteString(s.String())
   153  			sb.WriteString(";\n")
   154  		}
   155  		input = sb.String()
   156  	}
   157  	for _, m := range stringMutators {
   158  		s, ch := m.MutateString(rng, input)
   159  		if ch {
   160  			input = s
   161  			changed = true
   162  		}
   163  	}
   164  	return input, changed
   165  }
   166  
   167  // randNonNegInt returns a random non-negative integer. It attempts to
   168  // distribute it over powers of 10.
   169  func randNonNegInt(rng *rand.Rand) int64 {
   170  	var v int64
   171  	if n := rng.Intn(20); n == 0 {
   172  		// v == 0
   173  	} else if n <= 10 {
   174  		v = rng.Int63n(10) + 1
   175  		for i := 0; i < n; i++ {
   176  			v *= 10
   177  		}
   178  	} else {
   179  		v = rng.Int63()
   180  	}
   181  	return v
   182  }
   183  
   184  func statisticsMutator(
   185  	rng *rand.Rand, stmts []tree.Statement,
   186  ) (mutated []tree.Statement, changed bool) {
   187  	for _, stmt := range stmts {
   188  		create, ok := stmt.(*tree.CreateTable)
   189  		if !ok {
   190  			continue
   191  		}
   192  		alter := &tree.AlterTable{
   193  			Table: create.Table.ToUnresolvedObjectName(),
   194  		}
   195  		rowCount := randNonNegInt(rng)
   196  		cols := map[tree.Name]*tree.ColumnTableDef{}
   197  		colStats := map[tree.Name]*stats.JSONStatistic{}
   198  		makeHistogram := func(col *tree.ColumnTableDef) {
   199  			// If an index appeared before a column definition, col
   200  			// can be nil.
   201  			if col == nil {
   202  				return
   203  			}
   204  			n := rng.Intn(10)
   205  			seen := map[string]bool{}
   206  			colType := tree.MustBeStaticallyKnownType(col.Type)
   207  			h := stats.HistogramData{
   208  				ColumnType: colType,
   209  			}
   210  			for i := 0; i < n; i++ {
   211  				upper := sqlbase.RandDatumWithNullChance(rng, colType, 0)
   212  				if upper == tree.DNull {
   213  					continue
   214  				}
   215  				enc, err := sqlbase.EncodeTableKey(nil, upper, encoding.Ascending)
   216  				if err != nil {
   217  					panic(err)
   218  				}
   219  				if es := string(enc); seen[es] {
   220  					continue
   221  				} else {
   222  					seen[es] = true
   223  				}
   224  				numRange := randNonNegInt(rng)
   225  				var distinctRange float64
   226  				// distinctRange should be <= numRange.
   227  				switch rng.Intn(3) {
   228  				case 0:
   229  					// 0
   230  				case 1:
   231  					distinctRange = float64(numRange)
   232  				default:
   233  					distinctRange = rng.Float64() * float64(numRange)
   234  				}
   235  
   236  				h.Buckets = append(h.Buckets, stats.HistogramData_Bucket{
   237  					NumEq:         randNonNegInt(rng),
   238  					NumRange:      numRange,
   239  					DistinctRange: distinctRange,
   240  					UpperBound:    enc,
   241  				})
   242  			}
   243  			sort.Slice(h.Buckets, func(i, j int) bool {
   244  				return bytes.Compare(h.Buckets[i].UpperBound, h.Buckets[j].UpperBound) < 0
   245  			})
   246  			// The first bucket must have numrange = 0, and thus
   247  			// distinctrange = 0 as well.
   248  			if len(h.Buckets) > 0 {
   249  				h.Buckets[0].NumRange = 0
   250  				h.Buckets[0].DistinctRange = 0
   251  			}
   252  			stat := colStats[col.Name]
   253  			if err := stat.SetHistogram(&h); err != nil {
   254  				panic(err)
   255  			}
   256  		}
   257  		for _, def := range create.Defs {
   258  			switch def := def.(type) {
   259  			case *tree.ColumnTableDef:
   260  				var nullCount, distinctCount uint64
   261  				if rowCount > 0 {
   262  					if def.Nullable.Nullability != tree.NotNull {
   263  						nullCount = uint64(rng.Int63n(rowCount))
   264  					}
   265  					distinctCount = uint64(rng.Int63n(rowCount))
   266  				}
   267  				cols[def.Name] = def
   268  				colStats[def.Name] = &stats.JSONStatistic{
   269  					Name:          "__auto__",
   270  					CreatedAt:     "2000-01-01 00:00:00+00:00",
   271  					RowCount:      uint64(rowCount),
   272  					Columns:       []string{def.Name.String()},
   273  					DistinctCount: distinctCount,
   274  					NullCount:     nullCount,
   275  				}
   276  				if def.Unique || def.PrimaryKey.IsPrimaryKey {
   277  					makeHistogram(def)
   278  				}
   279  			case *tree.IndexTableDef:
   280  				makeHistogram(cols[def.Columns[0].Column])
   281  			case *tree.UniqueConstraintTableDef:
   282  				makeHistogram(cols[def.Columns[0].Column])
   283  			}
   284  		}
   285  		if len(colStats) > 0 {
   286  			var allStats []*stats.JSONStatistic
   287  			for _, cs := range colStats {
   288  				allStats = append(allStats, cs)
   289  			}
   290  			b, err := json.Marshal(allStats)
   291  			if err != nil {
   292  				// Should not happen.
   293  				panic(err)
   294  			}
   295  			alter.Cmds = append(alter.Cmds, &tree.AlterTableInjectStats{
   296  				Stats: tree.NewDString(string(b)),
   297  			})
   298  			stmts = append(stmts, alter)
   299  			changed = true
   300  		}
   301  	}
   302  	return stmts, changed
   303  }
   304  
   305  func foreignKeyMutator(
   306  	rng *rand.Rand, stmts []tree.Statement,
   307  ) (mutated []tree.Statement, changed bool) {
   308  	// Find columns in the tables.
   309  	cols := map[tree.TableName][]*tree.ColumnTableDef{}
   310  	byName := map[tree.TableName]*tree.CreateTable{}
   311  
   312  	// Keep track of referencing columns since we have a limitation that a
   313  	// column can only be used by one FK.
   314  	usedCols := map[tree.TableName]map[tree.Name]bool{}
   315  
   316  	// Keep track of table dependencies to prevent circular dependencies.
   317  	dependsOn := map[tree.TableName]map[tree.TableName]bool{}
   318  
   319  	var tables []*tree.CreateTable
   320  	for _, stmt := range stmts {
   321  		table, ok := stmt.(*tree.CreateTable)
   322  		if !ok {
   323  			continue
   324  		}
   325  		tables = append(tables, table)
   326  		byName[table.Table] = table
   327  		usedCols[table.Table] = map[tree.Name]bool{}
   328  		dependsOn[table.Table] = map[tree.TableName]bool{}
   329  		for _, def := range table.Defs {
   330  			switch def := def.(type) {
   331  			case *tree.ColumnTableDef:
   332  				cols[table.Table] = append(cols[table.Table], def)
   333  			}
   334  		}
   335  	}
   336  	if len(tables) == 0 {
   337  		return stmts, false
   338  	}
   339  
   340  	toNames := func(cols []*tree.ColumnTableDef) tree.NameList {
   341  		names := make(tree.NameList, len(cols))
   342  		for i, c := range cols {
   343  			names[i] = c.Name
   344  		}
   345  		return names
   346  	}
   347  
   348  	// We cannot mutate the table definitions themselves because 1) we
   349  	// don't know the order of dependencies (i.e., table 1 could reference
   350  	// table 4 which doesn't exist yet) and relatedly 2) we don't prevent
   351  	// circular dependencies. Instead, add new ALTER TABLE commands to the
   352  	// end of a list of statements.
   353  
   354  	// Create some FKs.
   355  	for rng.Intn(2) == 0 {
   356  		// Choose a random table.
   357  		table := tables[rng.Intn(len(tables))]
   358  		// Choose a random column subset.
   359  		var fkCols []*tree.ColumnTableDef
   360  		for _, c := range cols[table.Table] {
   361  			if usedCols[table.Table][c.Name] {
   362  				continue
   363  			}
   364  			fkCols = append(fkCols, c)
   365  		}
   366  		if len(fkCols) == 0 {
   367  			continue
   368  		}
   369  		rng.Shuffle(len(fkCols), func(i, j int) {
   370  			fkCols[i], fkCols[j] = fkCols[j], fkCols[i]
   371  		})
   372  		// Pick some randomly short prefix. I'm sure there's a closed
   373  		// form solution to this with a single call to rng.Intn but I'm
   374  		// not sure what to search for.
   375  		i := 1
   376  		for len(fkCols) > i && rng.Intn(2) == 0 {
   377  			i++
   378  		}
   379  		fkCols = fkCols[:i]
   380  
   381  		// Check if a table has the needed column types.
   382  	LoopTable:
   383  		for refTable, refCols := range cols {
   384  			// Prevent circular and self references because
   385  			// generating valid INSERTs could become impossible or
   386  			// difficult algorithmically.
   387  			if refTable == table.Table || len(refCols) < len(fkCols) {
   388  				continue
   389  			}
   390  
   391  			{
   392  				// To prevent circular references, find all transitive
   393  				// dependencies of refTable and make sure none of them
   394  				// are table.
   395  				stack := []tree.TableName{refTable}
   396  				for i := 0; i < len(stack); i++ {
   397  					curTable := stack[i]
   398  					if curTable == table.Table {
   399  						// table was trying to add a dependency
   400  						// to refTable, but refTable already
   401  						// depends on table (directly or
   402  						// indirectly).
   403  						continue LoopTable
   404  					}
   405  					for t := range dependsOn[curTable] {
   406  						stack = append(stack, t)
   407  					}
   408  				}
   409  			}
   410  
   411  			// We found a table with enough columns. Check if it
   412  			// has some columns that are needed types. In order
   413  			// to not use columns multiple times, keep track of
   414  			// available columns.
   415  			availCols := append([]*tree.ColumnTableDef(nil), refCols...)
   416  			var usingCols []*tree.ColumnTableDef
   417  			for len(availCols) > 0 && len(usingCols) < len(fkCols) {
   418  				fkCol := fkCols[len(usingCols)]
   419  				found := false
   420  				for refI, refCol := range availCols {
   421  					fkColType := tree.MustBeStaticallyKnownType(fkCol.Type)
   422  					refColType := tree.MustBeStaticallyKnownType(refCol.Type)
   423  					if fkColType.Equivalent(refColType) {
   424  						usingCols = append(usingCols, refCol)
   425  						availCols = append(availCols[:refI], availCols[refI+1:]...)
   426  						found = true
   427  						break
   428  					}
   429  				}
   430  				if !found {
   431  					continue LoopTable
   432  				}
   433  			}
   434  			// If we didn't find enough columns, try another table.
   435  			if len(usingCols) != len(fkCols) {
   436  				continue
   437  			}
   438  
   439  			// Found a suitable table.
   440  			// TODO(mjibson): prevent the creation of unneeded
   441  			// unique indexes. One may already exist with the
   442  			// correct prefix.
   443  			ref := byName[refTable]
   444  			refColumns := make(tree.IndexElemList, len(usingCols))
   445  			for i, c := range usingCols {
   446  				refColumns[i].Column = c.Name
   447  			}
   448  			for _, c := range fkCols {
   449  				usedCols[table.Table][c.Name] = true
   450  			}
   451  			dependsOn[table.Table][ref.Table] = true
   452  			ref.Defs = append(ref.Defs, &tree.UniqueConstraintTableDef{
   453  				IndexTableDef: tree.IndexTableDef{
   454  					Columns: refColumns,
   455  				},
   456  			})
   457  
   458  			match := tree.MatchSimple
   459  			// TODO(mjibson): Set match once #42498 is fixed.
   460  			var actions tree.ReferenceActions
   461  			if rng.Intn(2) == 0 {
   462  				actions.Delete = randAction(rng, table)
   463  			}
   464  			if rng.Intn(2) == 0 {
   465  				actions.Update = randAction(rng, table)
   466  			}
   467  			stmts = append(stmts, &tree.AlterTable{
   468  				Table: table.Table.ToUnresolvedObjectName(),
   469  				Cmds: tree.AlterTableCmds{&tree.AlterTableAddConstraint{
   470  					ConstraintDef: &tree.ForeignKeyConstraintTableDef{
   471  						Table:    ref.Table,
   472  						FromCols: toNames(fkCols),
   473  						ToCols:   toNames(usingCols),
   474  						Actions:  actions,
   475  						Match:    match,
   476  					},
   477  				}},
   478  			})
   479  			changed = true
   480  			break
   481  		}
   482  	}
   483  
   484  	return stmts, changed
   485  }
   486  
   487  func randAction(rng *rand.Rand, table *tree.CreateTable) tree.ReferenceAction {
   488  	const highestAction = tree.Cascade
   489  	// Find a valid action. Depending on the random action chosen, we have
   490  	// to verify some validity conditions.
   491  Loop:
   492  	for {
   493  		action := tree.ReferenceAction(rng.Intn(int(highestAction + 1)))
   494  		for _, def := range table.Defs {
   495  			col, ok := def.(*tree.ColumnTableDef)
   496  			if !ok {
   497  				continue
   498  			}
   499  			switch action {
   500  			case tree.SetNull:
   501  				if col.Nullable.Nullability == tree.NotNull {
   502  					continue Loop
   503  				}
   504  			case tree.SetDefault:
   505  				if col.DefaultExpr.Expr == nil && col.Nullable.Nullability == tree.NotNull {
   506  					continue Loop
   507  				}
   508  			}
   509  		}
   510  		return action
   511  	}
   512  }
   513  
   514  var postgresMutatorAtIndex = regexp.MustCompile(`@[\[\]\w]+`)
   515  
   516  func postgresMutator(rng *rand.Rand, q string) string {
   517  	q, _ = ApplyString(rng, q, postgresStatementMutator)
   518  
   519  	for from, to := range map[string]string{
   520  		":::":     "::",
   521  		"STRING":  "TEXT",
   522  		"BYTES":   "BYTEA",
   523  		"FLOAT4":  "FLOAT8",
   524  		"INT2":    "INT8",
   525  		"INT4":    "INT8",
   526  		"STORING": "INCLUDE",
   527  	} {
   528  		q = strings.Replace(q, from, to, -1)
   529  	}
   530  	q = postgresMutatorAtIndex.ReplaceAllString(q, "")
   531  	return q
   532  }
   533  
   534  // postgresStatementMutator removes cockroach-only things from CREATE TABLE and
   535  // ALTER TABLE.
   536  var postgresStatementMutator MultiStatementMutation = func(rng *rand.Rand, stmts []tree.Statement) (mutated []tree.Statement, changed bool) {
   537  	for _, stmt := range stmts {
   538  		switch stmt := stmt.(type) {
   539  		case *tree.SetClusterSetting:
   540  			continue
   541  		case *tree.CreateTable:
   542  			if stmt.Interleave != nil {
   543  				stmt.Interleave = nil
   544  				changed = true
   545  			}
   546  			if stmt.PartitionBy != nil {
   547  				stmt.PartitionBy = nil
   548  				changed = true
   549  			}
   550  			for i := 0; i < len(stmt.Defs); i++ {
   551  				switch def := stmt.Defs[i].(type) {
   552  				case *tree.FamilyTableDef:
   553  					// Remove.
   554  					stmt.Defs = append(stmt.Defs[:i], stmt.Defs[i+1:]...)
   555  					i--
   556  					changed = true
   557  				case *tree.ColumnTableDef:
   558  					if def.HasColumnFamily() {
   559  						def.Family.Name = ""
   560  						def.Family.Create = false
   561  						changed = true
   562  					}
   563  				case *tree.UniqueConstraintTableDef:
   564  					if def.Interleave != nil {
   565  						def.Interleave = nil
   566  						changed = true
   567  					}
   568  					if def.PartitionBy != nil {
   569  						def.PartitionBy = nil
   570  						changed = true
   571  					}
   572  				}
   573  			}
   574  		case *tree.AlterTable:
   575  			for i := 0; i < len(stmt.Cmds); i++ {
   576  				// Postgres doesn't have alter stats.
   577  				if _, ok := stmt.Cmds[i].(*tree.AlterTableInjectStats); ok {
   578  					stmt.Cmds = append(stmt.Cmds[:i], stmt.Cmds[i+1:]...)
   579  					i--
   580  					changed = true
   581  				}
   582  			}
   583  			// If there are no commands, don't add this statement.
   584  			if len(stmt.Cmds) == 0 {
   585  				continue
   586  			}
   587  		}
   588  		mutated = append(mutated, stmt)
   589  	}
   590  	return mutated, changed
   591  }
   592  
   593  func postgresCreateTableMutator(
   594  	rng *rand.Rand, stmts []tree.Statement,
   595  ) (mutated []tree.Statement, changed bool) {
   596  	for _, stmt := range stmts {
   597  		mutated = append(mutated, stmt)
   598  		switch stmt := stmt.(type) {
   599  		case *tree.CreateTable:
   600  			var newdefs tree.TableDefs
   601  			for _, def := range stmt.Defs {
   602  				switch def := def.(type) {
   603  				case *tree.IndexTableDef:
   604  					// Postgres doesn't support
   605  					// indexes in CREATE TABLE,
   606  					// so split them out to their
   607  					// own statement.
   608  					mutated = append(mutated, &tree.CreateIndex{
   609  						Name:     def.Name,
   610  						Table:    stmt.Table,
   611  						Inverted: def.Inverted,
   612  						Columns:  def.Columns,
   613  						Storing:  def.Storing,
   614  					})
   615  					changed = true
   616  				case *tree.UniqueConstraintTableDef:
   617  					if def.PrimaryKey {
   618  						// Postgres doesn't support descending PKs.
   619  						for i, col := range def.Columns {
   620  							if col.Direction != tree.DefaultDirection {
   621  								def.Columns[i].Direction = tree.DefaultDirection
   622  								changed = true
   623  							}
   624  						}
   625  						if def.Name != "" {
   626  							// Unset Name here because
   627  							// constaint names cannot
   628  							// be shared among tables,
   629  							// so multiple PK constraints
   630  							// named "primary" is an error.
   631  							def.Name = ""
   632  							changed = true
   633  						}
   634  						newdefs = append(newdefs, def)
   635  						break
   636  					}
   637  					mutated = append(mutated, &tree.CreateIndex{
   638  						Name:     def.Name,
   639  						Table:    stmt.Table,
   640  						Unique:   true,
   641  						Inverted: def.Inverted,
   642  						Columns:  def.Columns,
   643  						Storing:  def.Storing,
   644  					})
   645  					changed = true
   646  				default:
   647  					newdefs = append(newdefs, def)
   648  				}
   649  			}
   650  			stmt.Defs = newdefs
   651  		}
   652  	}
   653  	return mutated, changed
   654  }