github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/props/volatility.go (about) 1 // Copyright 2020 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 props 12 13 import "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 14 15 // VolatilitySet tracks the set of operator volatilities contained inside an 16 // expression. See tree.Volatility for more info on volatility values. 17 // 18 // The reason why we use a set (rather than the "maximum" volatility) is that 19 // for plan caching purposes, we want to distinguish the case when a stable 20 // operator is used - regardless of whether a volatile operator is used. For 21 // example, consider these two statements: 22 // (1) INSERT INTO t VALUES (gen_random_uuid(), '2020-10-09') 23 // (2) INSERT INTO t VALUES (gen_random_uuid(), now()) 24 // For (1) we can cache the final optimized plan. For (2), we can only cache the 25 // memo if we don't constant fold stable operators, and subsequently fold them 26 // each time we try to execute an instance of the query. 27 // 28 // TODO(radu): transfer the comment for CanHaveSideEffects here clarifying the 29 // optimizer policy around volatility and side-effects. 30 type VolatilitySet uint8 31 32 // Add a volatility to the set. 33 func (vs *VolatilitySet) Add(v tree.Volatility) { 34 *vs |= volatilityBit(v) 35 } 36 37 // AddImmutable is a convenience shorthand for adding VolatilityImmutable. 38 func (vs *VolatilitySet) AddImmutable() { 39 vs.Add(tree.VolatilityImmutable) 40 } 41 42 // AddStable is a convenience shorthand for adding VolatilityStable. 43 func (vs *VolatilitySet) AddStable() { 44 vs.Add(tree.VolatilityStable) 45 } 46 47 // AddVolatile is a convenience shorthand for adding VolatilityVolatile. 48 func (vs *VolatilitySet) AddVolatile() { 49 vs.Add(tree.VolatilityVolatile) 50 } 51 52 // UnionWith sets the receiver to the union of the two volatility sets. 53 func (vs *VolatilitySet) UnionWith(other VolatilitySet) { 54 *vs = *vs | other 55 } 56 57 // IsLeakProof returns true if the set is empty or only contains 58 // VolatilityLeakProof. 59 func (vs VolatilitySet) IsLeakProof() bool { 60 return vs == 0 || vs == volatilityBit(tree.VolatilityLeakProof) 61 } 62 63 // HasStable returns true if the set contains VolatilityStable. 64 func (vs VolatilitySet) HasStable() bool { 65 return (vs & volatilityBit(tree.VolatilityStable)) != 0 66 } 67 68 // HasVolatile returns true if the set contains VolatilityVolatile. 69 func (vs VolatilitySet) HasVolatile() bool { 70 return (vs & volatilityBit(tree.VolatilityVolatile)) != 0 71 } 72 73 func (vs VolatilitySet) String() string { 74 // The only properties we care about are IsLeakProof(), HasStable() and 75 // HasVolatile(). We print one of the strings below: 76 // 77 // String | IsLeakProof | HasStable | HasVolatile 78 // -------------------+-------------+-----------+------------- 79 // "leak-proof" | true | false | false 80 // "immutable" | false | false | false 81 // "stable" | false | true | false 82 // "volatile" | false | false | true 83 // "stable+volatile" | false | true | true 84 // 85 // These are the only valid combinations for these properties. 86 // 87 if vs.IsLeakProof() { 88 return "leak-proof" 89 } 90 hasStable := vs.HasStable() 91 hasVolatile := vs.HasVolatile() 92 switch { 93 case !hasStable && !hasVolatile: 94 return "immutable" 95 case hasStable && !hasVolatile: 96 return "stable" 97 case hasVolatile && !hasStable: 98 return "volatile" 99 default: 100 return "stable+volatile" 101 } 102 } 103 104 func volatilityBit(v tree.Volatility) VolatilitySet { 105 return 1 << VolatilitySet(v) 106 }