github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/props/cardinality.go (about) 1 // Copyright 2018 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 ( 14 "fmt" 15 "math" 16 ) 17 18 // ZeroCardinality indicates that no rows will be returned by expression. 19 var ZeroCardinality = Cardinality{} 20 21 // OneCardinality indicates that exactly one row will be returned by expression. 22 var OneCardinality = Cardinality{Min: 1, Max: 1} 23 24 // AnyCardinality indicates that any number of rows can be returned by an 25 // expression. 26 var AnyCardinality = Cardinality{Min: 0, Max: math.MaxUint32} 27 28 // Cardinality is the number of rows that can be returned by a relational 29 // expression. Both Min and Max are inclusive bounds. If Max = math.MaxUint32, 30 // that indicates there is no limit to the number of returned rows. Max should 31 // always be >= Min, or method results are undefined. Cardinality is determined 32 // from the relational properties, and are "hard" bounds that are never 33 // incorrect. This constrasts with row cardinality derived by the statistics 34 // code, which are only estimates and may be incorrect. 35 type Cardinality struct { 36 Min uint32 37 Max uint32 38 } 39 40 // IsZero returns true if the expression never returns any rows. 41 func (c Cardinality) IsZero() bool { 42 return c.Min == 0 && c.Max == 0 43 } 44 45 // IsOne returns true if the expression always returns one row. 46 func (c Cardinality) IsOne() bool { 47 return c.Min == 1 && c.Max == 1 48 } 49 50 // IsZeroOrOne is true if the expression never returns more than one row. 51 func (c Cardinality) IsZeroOrOne() bool { 52 return c.Max <= 1 53 } 54 55 // CanBeZero is true if the expression can return zero rows. 56 func (c Cardinality) CanBeZero() bool { 57 return c.Min == 0 58 } 59 60 // AsLowAs ratchets the min bound downwards in order to ensure that it allows 61 // values that are >= the min value. 62 func (c Cardinality) AsLowAs(min uint32) Cardinality { 63 return Cardinality{ 64 Min: minVal(c.Min, min), 65 Max: c.Max, 66 } 67 } 68 69 // Limit ratchets the bounds downwards so that they're no bigger than the given 70 // max value. 71 func (c Cardinality) Limit(max uint32) Cardinality { 72 return Cardinality{ 73 Min: minVal(c.Min, max), 74 Max: minVal(c.Max, max), 75 } 76 } 77 78 // AtLeast ratchets the bounds upwards so that they're at least as large as the 79 // bounds in the given cardinality. 80 func (c Cardinality) AtLeast(other Cardinality) Cardinality { 81 return Cardinality{ 82 Min: maxVal(c.Min, other.Min), 83 Max: maxVal(c.Max, other.Max), 84 } 85 } 86 87 // Add sums the min and max bounds to get a combined count of rows. 88 func (c Cardinality) Add(other Cardinality) Cardinality { 89 // Make sure to detect overflow. 90 min := c.Min + other.Min 91 if min < c.Min { 92 min = math.MaxUint32 93 } 94 max := c.Max + other.Max 95 if max < c.Max { 96 max = math.MaxUint32 97 } 98 return Cardinality{Min: min, Max: max} 99 } 100 101 // Product multiples the min and max bounds to get the combined product of rows. 102 func (c Cardinality) Product(other Cardinality) Cardinality { 103 // Prevent overflow by using 64-bit multiplication. 104 min := uint64(c.Min) * uint64(other.Min) 105 if min > math.MaxUint32 { 106 min = math.MaxUint32 107 } 108 max := uint64(c.Max) * uint64(other.Max) 109 if max > math.MaxUint32 { 110 max = math.MaxUint32 111 } 112 return Cardinality{Min: uint32(min), Max: uint32(max)} 113 } 114 115 // Skip subtracts the given number of rows from the min and max bounds to 116 // account for skipped rows. 117 func (c Cardinality) Skip(rows uint32) Cardinality { 118 min := c.Min - rows 119 if min > c.Min { 120 min = 0 121 } 122 if c.Max == math.MaxUint32 { 123 // No upper bound, so treat it as if it's infinity. 124 return Cardinality{Min: min, Max: c.Max} 125 } 126 max := c.Max - rows 127 if max > c.Max { 128 max = 0 129 } 130 return Cardinality{Min: min, Max: max} 131 } 132 133 func (c Cardinality) String() string { 134 if c.Max == math.MaxUint32 { 135 return fmt.Sprintf("[%d - ]", c.Min) 136 } 137 return fmt.Sprintf("[%d - %d]", c.Min, c.Max) 138 } 139 140 func minVal(a, b uint32) uint32 { 141 if a <= b { 142 return a 143 } 144 return b 145 } 146 147 func maxVal(a, b uint32) uint32 { 148 if a >= b { 149 return a 150 } 151 return b 152 }