github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/internal/sqlsmith/setup.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 sqlsmith
    12  
    13  import (
    14  	"math/rand"
    15  	"sort"
    16  	"strings"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/sql/mutations"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    20  )
    21  
    22  // Setup generates a SQL query that can be executed to initialize a database
    23  // for smithing.
    24  type Setup func(*rand.Rand) string
    25  
    26  // Setups is a collection of useful initial table states.
    27  var Setups = map[string]Setup{
    28  	"empty": stringSetup(""),
    29  	// seed is a SQL statement that creates a table with most data types
    30  	// and some sample rows.
    31  	"seed": stringSetup(seedTable),
    32  	// seed-vec is like seed except only types supported by vectorized
    33  	// execution are used.
    34  	"seed-vec":    stringSetup(vecSeedTable),
    35  	"rand-tables": randTables,
    36  }
    37  
    38  var setupNames = func() []string {
    39  	var ret []string
    40  	for k := range Setups {
    41  		ret = append(ret, k)
    42  	}
    43  	sort.Strings(ret)
    44  	return ret
    45  }()
    46  
    47  // RandSetup returns a random key from Setups.
    48  func RandSetup(r *rand.Rand) string {
    49  	n := r.Intn(len(setupNames))
    50  	return setupNames[n]
    51  }
    52  
    53  func stringSetup(s string) Setup {
    54  	return func(*rand.Rand) string {
    55  		return s
    56  	}
    57  }
    58  
    59  func randTables(r *rand.Rand) string {
    60  	var sb strings.Builder
    61  	// Since we use the stats mutator, disable auto stats generation.
    62  	sb.WriteString(`
    63  		SET CLUSTER SETTING sql.stats.automatic_collection.enabled = false;
    64  		SET CLUSTER SETTING sql.stats.histogram_collection.enabled = false;
    65  	`)
    66  
    67  	stmts := sqlbase.RandCreateTables(r, "table", r.Intn(5)+1,
    68  		mutations.ForeignKeyMutator,
    69  		mutations.StatisticsMutator,
    70  	)
    71  
    72  	for _, stmt := range stmts {
    73  		sb.WriteString(stmt.String())
    74  		sb.WriteString(";\n")
    75  	}
    76  
    77  	// TODO(mjibson): add random INSERTs.
    78  
    79  	return sb.String()
    80  }
    81  
    82  const (
    83  	seedTable = `
    84  CREATE TABLE IF NOT EXISTS seed AS
    85  	SELECT
    86  		g::INT2 AS _int2,
    87  		g::INT4 AS _int4,
    88  		g::INT8 AS _int8,
    89  		g::FLOAT4 AS _float4,
    90  		g::FLOAT8 AS _float8,
    91  		'2001-01-01'::DATE + g AS _date,
    92  		'2001-01-01'::TIMESTAMP + g * '1 day'::INTERVAL AS _timestamp,
    93  		'2001-01-01'::TIMESTAMPTZ + g * '1 day'::INTERVAL AS _timestamptz,
    94  		g * '1 day'::INTERVAL AS _interval,
    95  		g % 2 = 1 AS _bool,
    96  		g::DECIMAL AS _decimal,
    97  		g::STRING AS _string,
    98  		g::STRING::BYTES AS _bytes,
    99  		substring('00000000-0000-0000-0000-' || g::STRING || '00000000000', 1, 36)::UUID AS _uuid,
   100  		'0.0.0.0'::INET + g AS _inet,
   101  		g::STRING::JSONB AS _jsonb
   102  	FROM
   103  		generate_series(1, 5) AS g;
   104  
   105  INSERT INTO seed DEFAULT VALUES;
   106  CREATE INDEX on seed (_int8, _float8, _date);
   107  CREATE INVERTED INDEX on seed (_jsonb);
   108  `
   109  
   110  	vecSeedTable = `
   111  CREATE TABLE IF NOT EXISTS seed_vec AS
   112  	SELECT
   113  		g::INT2 AS _int2,
   114  		g::INT4 AS _int4,
   115  		g::INT8 AS _int8,
   116  		g::FLOAT8 AS _float8,
   117  		'2001-01-01'::DATE + g AS _date,
   118  		'2001-01-01'::TIMESTAMP + g * '1 day'::INTERVAL AS _timestamp,
   119  		'2001-01-01'::TIMESTAMPTZ + g * '1 day'::INTERVAL AS _timestamptz,
   120  		g * '1 day'::INTERVAL AS _interval,
   121  		g % 2 = 1 AS _bool,
   122  		g::DECIMAL AS _decimal,
   123  		g::STRING AS _string,
   124  		g::STRING::BYTES AS _bytes,
   125  		substring('00000000-0000-0000-0000-' || g::STRING || '00000000000', 1, 36)::UUID AS _uuid
   126  	FROM
   127  		generate_series(1, 5) AS g;
   128  
   129  INSERT INTO seed_vec DEFAULT VALUES;
   130  CREATE INDEX on seed_vec (_int8, _float8, _date);
   131  `
   132  )
   133  
   134  // SettingFunc generates a Setting.
   135  type SettingFunc func(*rand.Rand) Setting
   136  
   137  // Setting defines options and execution modes for a Smither.
   138  type Setting struct {
   139  	Options []SmitherOption
   140  	Mode    ExecMode
   141  }
   142  
   143  // ExecMode definitions define how a Setting can be executed.
   144  type ExecMode int
   145  
   146  const (
   147  	// NoParallel indicates that, if determinism is desired, this Setting
   148  	// should not be executed in parallel.
   149  	NoParallel ExecMode = iota
   150  	// Parallel indicates that this Setting can be executed in parallel and
   151  	// still preserve determinism.
   152  	Parallel
   153  )
   154  
   155  // Settings is a collection of useful Setting options.
   156  var Settings = map[string]SettingFunc{
   157  	"default":           staticSetting(Parallel),
   158  	"no-mutations":      staticSetting(Parallel, DisableMutations()),
   159  	"no-ddl":            staticSetting(NoParallel, DisableDDLs()),
   160  	"default+rand":      randSetting(Parallel),
   161  	"no-mutations+rand": randSetting(Parallel, DisableMutations()),
   162  	"no-ddl+rand":       randSetting(NoParallel, DisableDDLs()),
   163  	"ddl-nodrop":        randSetting(NoParallel, OnlyNoDropDDLs()),
   164  }
   165  
   166  // SettingVectorize is the setting for vectorizable. It is not included in
   167  // Settings because it has type restrictions during CREATE TABLE, but Settings
   168  // is designed to be used with anything in Setups, which may violate that
   169  // restriction.
   170  var SettingVectorize = staticSetting(Parallel, Vectorizable())
   171  
   172  var settingNames = func() []string {
   173  	var ret []string
   174  	for k := range Settings {
   175  		ret = append(ret, k)
   176  	}
   177  	sort.Strings(ret)
   178  	return ret
   179  }()
   180  
   181  // RandSetting returns a random key from Settings.
   182  func RandSetting(r *rand.Rand) string {
   183  	return settingNames[r.Intn(len(settingNames))]
   184  }
   185  
   186  func staticSetting(mode ExecMode, opts ...SmitherOption) SettingFunc {
   187  	return func(*rand.Rand) Setting {
   188  		return Setting{
   189  			Options: opts,
   190  			Mode:    mode,
   191  		}
   192  	}
   193  }
   194  
   195  func randSetting(mode ExecMode, staticOpts ...SmitherOption) SettingFunc {
   196  	return func(r *rand.Rand) Setting {
   197  		// Generate a random subset of randOptions.
   198  		opts := append([]SmitherOption(nil), randOptions...)
   199  		r.Shuffle(len(opts), func(i, j int) {
   200  			opts[i], opts[j] = opts[j], opts[i]
   201  		})
   202  		// Use between (inclusive) none and all of the shuffled options.
   203  		opts = opts[:r.Intn(len(opts)+1)]
   204  		opts = append(opts, staticOpts...)
   205  		return Setting{
   206  			Options: opts,
   207  			Mode:    mode,
   208  		}
   209  	}
   210  }
   211  
   212  // randOptions is the list of SmitherOptions that can be chosen from randomly
   213  // that are guaranteed to not add mutations or remove determinism from
   214  // generated queries.
   215  var randOptions = []SmitherOption{
   216  	AvoidConsts(),
   217  	CompareMode(),
   218  	DisableLimits(),
   219  	DisableWindowFuncs(),
   220  	DisableWith(),
   221  	PostgresMode(),
   222  	SimpleDatums(),
   223  
   224  	// Vectorizable() is not included here because it assumes certain
   225  	// types don't exist in table schemas. Since we don't yet have a way to
   226  	// verify that assumption, don't enable this.
   227  }