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 }