github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/set_cluster_setting.go (about) 1 // Copyright 2017 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 sql 12 13 import ( 14 "context" 15 "strconv" 16 "strings" 17 "time" 18 19 "github.com/cockroachdb/cockroach/pkg/kv" 20 "github.com/cockroachdb/cockroach/pkg/security" 21 "github.com/cockroachdb/cockroach/pkg/server/telemetry" 22 "github.com/cockroachdb/cockroach/pkg/settings" 23 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 24 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 25 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 26 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 27 "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" 28 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 29 "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" 30 "github.com/cockroachdb/cockroach/pkg/sql/stats" 31 "github.com/cockroachdb/cockroach/pkg/sql/types" 32 "github.com/cockroachdb/cockroach/pkg/util/humanizeutil" 33 "github.com/cockroachdb/cockroach/pkg/util/log" 34 "github.com/cockroachdb/cockroach/pkg/util/retry" 35 "github.com/cockroachdb/errors" 36 ) 37 38 // setClusterSettingNode represents a SET CLUSTER SETTING statement. 39 type setClusterSettingNode struct { 40 name string 41 st *cluster.Settings 42 setting settings.WritableSetting 43 // If value is nil, the setting should be reset. 44 value tree.TypedExpr 45 } 46 47 // SetClusterSetting sets session variables. 48 // Privileges: super user. 49 func (p *planner) SetClusterSetting( 50 ctx context.Context, n *tree.SetClusterSetting, 51 ) (planNode, error) { 52 if err := p.RequireAdminRole(ctx, "SET CLUSTER SETTING"); err != nil { 53 return nil, err 54 } 55 56 if !p.execCfg.TenantTestingKnobs.CanSetClusterSettings() && !p.execCfg.Codec.ForSystemTenant() { 57 // Setting cluster settings is disabled for phase 2 tenants if a test does 58 // not explicitly allow for setting in-memory cluster settings. 59 return nil, pgerror.Newf(pgcode.InsufficientPrivilege, "only the system tenant can SET CLUSTER SETTING") 60 } 61 62 name := strings.ToLower(n.Name) 63 st := p.EvalContext().Settings 64 v, ok := settings.Lookup(name, settings.LookupForLocalAccess) 65 if !ok { 66 return nil, errors.Errorf("unknown cluster setting '%s'", name) 67 } 68 69 setting, ok := v.(settings.WritableSetting) 70 if !ok { 71 return nil, errors.AssertionFailedf("expected writable setting, got %T", v) 72 } 73 74 if _, ok := setting.(*settings.StateMachineSetting); ok && p.execCfg.TenantTestingKnobs.CanSetClusterSettings() { 75 // A tenant that is allowed to set in-memory cluster settings is attempting 76 // to set a state machine setting, which is disallowed due to complexity. 77 return nil, pgerror.Newf(pgcode.InsufficientPrivilege, "only the system tenant can set state machine settings") 78 } 79 80 var value tree.TypedExpr 81 if n.Value != nil { 82 // For DEFAULT, let the value reference be nil. That's a RESET in disguise. 83 if _, ok := n.Value.(tree.DefaultVal); !ok { 84 expr := n.Value 85 expr = unresolvedNameToStrVal(expr) 86 87 var requiredType *types.T 88 switch setting.(type) { 89 case *settings.StringSetting, *settings.StateMachineSetting, *settings.ByteSizeSetting: 90 requiredType = types.String 91 case *settings.BoolSetting: 92 requiredType = types.Bool 93 case *settings.IntSetting: 94 requiredType = types.Int 95 case *settings.FloatSetting: 96 requiredType = types.Float 97 case *settings.EnumSetting: 98 requiredType = types.Any 99 case *settings.DurationSetting: 100 requiredType = types.Interval 101 default: 102 return nil, errors.Errorf("unsupported setting type %T", setting) 103 } 104 105 var dummyHelper tree.IndexedVarHelper 106 typed, err := p.analyzeExpr( 107 ctx, expr, nil, dummyHelper, requiredType, true, "SET CLUSTER SETTING "+name) 108 if err != nil { 109 return nil, err 110 } 111 112 value = typed 113 } else if _, isStateMachineSetting := setting.(*settings.StateMachineSetting); isStateMachineSetting { 114 return nil, errors.New("cannot RESET this cluster setting") 115 } 116 } 117 118 return &setClusterSettingNode{name: name, st: st, setting: setting, value: value}, nil 119 } 120 121 func (n *setClusterSettingNode) startExec(params runParams) error { 122 if !params.p.ExtendedEvalContext().TxnImplicit { 123 return errors.Errorf("SET CLUSTER SETTING cannot be used inside a transaction") 124 } 125 126 if !params.p.execCfg.Codec.ForSystemTenant() { 127 // Sanity check that this tenant is able to set in-memory settings. 128 if !params.p.execCfg.TenantTestingKnobs.CanSetClusterSettings() { 129 return errors.Errorf("tenants cannot set cluster settings, this permission should have been checked at plan time") 130 } 131 var encodedValue string 132 if n.value == nil { 133 encodedValue = n.setting.EncodedDefault() 134 } else { 135 value, err := n.value.Eval(params.p.EvalContext()) 136 if err != nil { 137 return err 138 } 139 if _, ok := n.setting.(*settings.StateMachineSetting); ok { 140 return errors.Errorf("tenants cannot change state machine settings, this should've been checked at plan time") 141 } 142 encodedValue, err = toSettingString(params.ctx, n.st, n.name, n.setting, value, nil /* prev */) 143 if err != nil { 144 return err 145 } 146 } 147 return params.p.execCfg.TenantTestingKnobs.ClusterSettingsUpdater.Set(n.name, encodedValue, n.setting.Typ()) 148 } 149 150 execCfg := params.extendedEvalCtx.ExecCfg 151 var expectedEncodedValue string 152 if err := execCfg.DB.Txn(params.ctx, func(ctx context.Context, txn *kv.Txn) error { 153 var reportedValue string 154 if n.value == nil { 155 reportedValue = "DEFAULT" 156 expectedEncodedValue = n.setting.EncodedDefault() 157 if _, err := execCfg.InternalExecutor.ExecEx( 158 ctx, "reset-setting", txn, 159 sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser}, 160 "DELETE FROM system.settings WHERE name = $1", n.name, 161 ); err != nil { 162 return err 163 } 164 } else { 165 value, err := n.value.Eval(params.p.EvalContext()) 166 if err != nil { 167 return err 168 } 169 reportedValue = tree.AsStringWithFlags(value, tree.FmtBareStrings) 170 var prev tree.Datum 171 if _, ok := n.setting.(*settings.StateMachineSetting); ok { 172 datums, err := execCfg.InternalExecutor.QueryRowEx( 173 ctx, "retrieve-prev-setting", txn, 174 sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser}, 175 "SELECT value FROM system.settings WHERE name = $1", n.name, 176 ) 177 if err != nil { 178 return err 179 } 180 if len(datums) == 0 { 181 // There is a SQL migration which adds this value. If it 182 // hasn't run yet, we can't update the version as we don't 183 // have good enough information about the current cluster 184 // version. 185 return errors.New("no persisted cluster version found, please retry later") 186 } 187 prev = datums[0] 188 } 189 encoded, err := toSettingString(ctx, n.st, n.name, n.setting, value, prev) 190 expectedEncodedValue = encoded 191 if err != nil { 192 return err 193 } 194 if _, err = execCfg.InternalExecutor.ExecEx( 195 ctx, "update-setting", txn, 196 sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser}, 197 `UPSERT INTO system.settings (name, value, "lastUpdated", "valueType") VALUES ($1, $2, now(), $3)`, 198 n.name, encoded, n.setting.Typ(), 199 ); err != nil { 200 return err 201 } 202 } 203 204 // Report tracked cluster settings via telemetry. 205 // TODO(justin): implement a more general mechanism for tracking these. 206 switch n.name { 207 case stats.AutoStatsClusterSettingName: 208 switch expectedEncodedValue { 209 case "true": 210 telemetry.Inc(sqltelemetry.TurnAutoStatsOnUseCounter) 211 case "false": 212 telemetry.Inc(sqltelemetry.TurnAutoStatsOffUseCounter) 213 } 214 case ConnAuditingClusterSettingName: 215 switch expectedEncodedValue { 216 case "true": 217 telemetry.Inc(sqltelemetry.TurnConnAuditingOnUseCounter) 218 case "false": 219 telemetry.Inc(sqltelemetry.TurnConnAuditingOffUseCounter) 220 } 221 case AuthAuditingClusterSettingName: 222 switch expectedEncodedValue { 223 case "true": 224 telemetry.Inc(sqltelemetry.TurnAuthAuditingOnUseCounter) 225 case "false": 226 telemetry.Inc(sqltelemetry.TurnAuthAuditingOffUseCounter) 227 } 228 case ReorderJoinsLimitClusterSettingName: 229 val, err := strconv.ParseInt(expectedEncodedValue, 10, 64) 230 if err != nil { 231 break 232 } 233 sqltelemetry.ReportJoinReorderLimit(int(val)) 234 case VectorizeClusterSettingName: 235 val, err := strconv.Atoi(expectedEncodedValue) 236 if err != nil { 237 break 238 } 239 validatedExecMode, isValid := sessiondata.VectorizeExecModeFromString(sessiondata.VectorizeExecMode(val).String()) 240 if !isValid { 241 break 242 } 243 telemetry.Inc(sqltelemetry.VecModeCounter(validatedExecMode.String())) 244 } 245 246 return MakeEventLogger(params.extendedEvalCtx.ExecCfg).InsertEventRecord( 247 ctx, 248 txn, 249 EventLogSetClusterSetting, 250 0, /* no target */ 251 int32(params.extendedEvalCtx.NodeID.SQLInstanceID()), 252 EventLogSetClusterSettingDetail{n.name, reportedValue, params.SessionData().User}, 253 ) 254 }); err != nil { 255 return err 256 } 257 258 if _, ok := n.setting.(*settings.StateMachineSetting); ok && n.value == nil { 259 // The "version" setting doesn't have a well defined "default" since it is 260 // set in a startup migration. 261 return nil 262 } 263 errNotReady := errors.New("setting updated but timed out waiting to read new value") 264 var observed string 265 err := retry.ForDuration(10*time.Second, func() error { 266 observed = n.setting.Encoded(&execCfg.Settings.SV) 267 if observed != expectedEncodedValue { 268 return errNotReady 269 } 270 return nil 271 }) 272 if err != nil { 273 log.Warningf( 274 params.ctx, "SET CLUSTER SETTING %q timed out waiting for value %q, observed %q", 275 n.name, expectedEncodedValue, observed, 276 ) 277 } 278 return err 279 } 280 281 func (n *setClusterSettingNode) Next(_ runParams) (bool, error) { return false, nil } 282 func (n *setClusterSettingNode) Values() tree.Datums { return nil } 283 func (n *setClusterSettingNode) Close(_ context.Context) {} 284 285 // toSettingString takes in a datum that's supposed to become the value for a 286 // Setting and validates it, returning the string representation of the new 287 // value as it needs to be inserted into the system.settings table. 288 // 289 // Args: 290 // prev: Only specified if the setting is a StateMachineSetting. Represents the 291 // current value of the setting, read from the system.settings table. 292 func toSettingString( 293 ctx context.Context, st *cluster.Settings, name string, s settings.Setting, d, prev tree.Datum, 294 ) (string, error) { 295 switch setting := s.(type) { 296 case *settings.StringSetting: 297 if s, ok := d.(*tree.DString); ok { 298 if err := setting.Validate(&st.SV, string(*s)); err != nil { 299 return "", err 300 } 301 return string(*s), nil 302 } 303 return "", errors.Errorf("cannot use %s %T value for string setting", d.ResolvedType(), d) 304 case *settings.StateMachineSetting: 305 if s, ok := d.(*tree.DString); ok { 306 dStr, ok := prev.(*tree.DString) 307 if !ok { 308 return "", errors.New("the existing value is not a string") 309 } 310 prevRawVal := []byte(string(*dStr)) 311 newBytes, err := setting.Validate(ctx, &st.SV, prevRawVal, string(*s)) 312 if err != nil { 313 return "", err 314 } 315 return string(newBytes), nil 316 } 317 return "", errors.Errorf("cannot use %s %T value for string setting", d.ResolvedType(), d) 318 case *settings.BoolSetting: 319 if b, ok := d.(*tree.DBool); ok { 320 return settings.EncodeBool(bool(*b)), nil 321 } 322 return "", errors.Errorf("cannot use %s %T value for bool setting", d.ResolvedType(), d) 323 case *settings.IntSetting: 324 if i, ok := d.(*tree.DInt); ok { 325 if err := setting.Validate(int64(*i)); err != nil { 326 return "", err 327 } 328 return settings.EncodeInt(int64(*i)), nil 329 } 330 return "", errors.Errorf("cannot use %s %T value for int setting", d.ResolvedType(), d) 331 case *settings.FloatSetting: 332 if f, ok := d.(*tree.DFloat); ok { 333 if err := setting.Validate(float64(*f)); err != nil { 334 return "", err 335 } 336 return settings.EncodeFloat(float64(*f)), nil 337 } 338 return "", errors.Errorf("cannot use %s %T value for float setting", d.ResolvedType(), d) 339 case *settings.EnumSetting: 340 if i, intOK := d.(*tree.DInt); intOK { 341 v, ok := setting.ParseEnum(settings.EncodeInt(int64(*i))) 342 if ok { 343 return settings.EncodeInt(v), nil 344 } 345 return "", errors.WithHintf(errors.Errorf("invalid integer value '%d' for enum setting", *i), setting.GetAvailableValuesAsHint()) 346 } else if s, ok := d.(*tree.DString); ok { 347 str := string(*s) 348 v, ok := setting.ParseEnum(str) 349 if ok { 350 return settings.EncodeInt(v), nil 351 } 352 return "", errors.WithHintf(errors.Errorf("invalid string value '%s' for enum setting", str), setting.GetAvailableValuesAsHint()) 353 } 354 return "", errors.Errorf("cannot use %s %T value for enum setting, must be int or string", d.ResolvedType(), d) 355 case *settings.ByteSizeSetting: 356 if s, ok := d.(*tree.DString); ok { 357 bytes, err := humanizeutil.ParseBytes(string(*s)) 358 if err != nil { 359 return "", err 360 } 361 if err := setting.Validate(bytes); err != nil { 362 return "", err 363 } 364 return settings.EncodeInt(bytes), nil 365 } 366 return "", errors.Errorf("cannot use %s %T value for byte size setting", d.ResolvedType(), d) 367 case *settings.DurationSetting: 368 if f, ok := d.(*tree.DInterval); ok { 369 if f.Duration.Months > 0 || f.Duration.Days > 0 { 370 return "", errors.Errorf("cannot use day or month specifiers: %s", d.String()) 371 } 372 d := time.Duration(f.Duration.Nanos()) * time.Nanosecond 373 if err := setting.Validate(d); err != nil { 374 return "", err 375 } 376 return settings.EncodeDuration(d), nil 377 } 378 return "", errors.Errorf("cannot use %s %T value for duration setting", d.ResolvedType(), d) 379 default: 380 return "", errors.Errorf("unsupported setting type %T", setting) 381 } 382 }