vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/helpers.go (about) 1 /* 2 Copyright 2022 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package operators 18 19 import ( 20 "fmt" 21 "sort" 22 23 "vitess.io/vitess/go/vt/sqlparser" 24 "vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops" 25 "vitess.io/vitess/go/vt/vtgate/planbuilder/operators/rewrite" 26 "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" 27 "vitess.io/vitess/go/vt/vtgate/semantics" 28 "vitess.io/vitess/go/vt/vtgate/vindexes" 29 ) 30 31 // Compact will optimise the operator tree into a smaller but equivalent version 32 func Compact(ctx *plancontext.PlanningContext, op ops.Operator) (ops.Operator, error) { 33 type compactable interface { 34 // Compact implement this interface for operators that have easy to see optimisations 35 Compact(ctx *plancontext.PlanningContext) (ops.Operator, rewrite.TreeIdentity, error) 36 } 37 38 newOp, err := rewrite.BottomUp(op, func(op ops.Operator) (ops.Operator, rewrite.TreeIdentity, error) { 39 newOp, ok := op.(compactable) 40 if !ok { 41 return op, rewrite.SameTree, nil 42 } 43 return newOp.Compact(ctx) 44 }) 45 return newOp, err 46 } 47 48 func CheckValid(op ops.Operator) error { 49 type checkable interface { 50 CheckValid() error 51 } 52 53 return rewrite.Visit(op, func(this ops.Operator) error { 54 if chk, ok := this.(checkable); ok { 55 return chk.CheckValid() 56 } 57 return nil 58 }) 59 } 60 61 func Clone(op ops.Operator) ops.Operator { 62 inputs := op.Inputs() 63 clones := make([]ops.Operator, len(inputs)) 64 for i, input := range inputs { 65 clones[i] = Clone(input) 66 } 67 return op.Clone(clones) 68 } 69 70 // TableIDIntroducer is used to signal that this operator introduces data from a new source 71 type TableIDIntroducer interface { 72 Introduces() semantics.TableSet 73 } 74 75 func TableID(op ops.Operator) (result semantics.TableSet) { 76 _ = rewrite.Visit(op, func(this ops.Operator) error { 77 if tbl, ok := this.(TableIDIntroducer); ok { 78 result = result.Merge(tbl.Introduces()) 79 } 80 return nil 81 }) 82 return 83 } 84 85 // TableUser is used to signal that this operator directly interacts with one or more tables 86 type TableUser interface { 87 TablesUsed() []string 88 } 89 90 func TablesUsed(op ops.Operator) []string { 91 addString, collect := collectSortedUniqueStrings() 92 _ = rewrite.Visit(op, func(this ops.Operator) error { 93 if tbl, ok := this.(TableUser); ok { 94 for _, u := range tbl.TablesUsed() { 95 addString(u) 96 } 97 } 98 return nil 99 }) 100 return collect() 101 } 102 103 func UnresolvedPredicates(op ops.Operator, st *semantics.SemTable) (result []sqlparser.Expr) { 104 type unresolved interface { 105 // UnsolvedPredicates returns any predicates that have dependencies on the given Operator and 106 // on the outside of it (a parent Select expression, any other table not used by Operator, etc). 107 // This is used for sub-queries. An example query could be: 108 // SELECT * FROM tbl WHERE EXISTS (SELECT 1 FROM otherTbl WHERE tbl.col = otherTbl.col) 109 // The subquery would have one unsolved predicate: `tbl.col = otherTbl.col` 110 // It's a predicate that belongs to the inner query, but it needs data from the outer query 111 // These predicates dictate which data we have to send from the outer side to the inner 112 UnsolvedPredicates(semTable *semantics.SemTable) []sqlparser.Expr 113 } 114 115 _ = rewrite.Visit(op, func(this ops.Operator) error { 116 if tbl, ok := this.(unresolved); ok { 117 result = append(result, tbl.UnsolvedPredicates(st)...) 118 } 119 120 return nil 121 }) 122 return 123 } 124 125 func CostOf(op ops.Operator) (cost int) { 126 type costly interface { 127 // Cost returns the cost for this operator. All the costly operators in the tree are summed together to get the 128 // total cost of the operator tree. 129 // TODO: We should really calculate this using cardinality estimation, 130 // but until then this is better than nothing 131 Cost() int 132 } 133 134 _ = rewrite.Visit(op, func(op ops.Operator) error { 135 if costlyOp, ok := op.(costly); ok { 136 cost += costlyOp.Cost() 137 } 138 return nil 139 }) 140 return 141 } 142 143 func QualifiedIdentifier(ks *vindexes.Keyspace, i sqlparser.IdentifierCS) string { 144 return QualifiedString(ks, i.String()) 145 } 146 147 func QualifiedString(ks *vindexes.Keyspace, s string) string { 148 return fmt.Sprintf("%s.%s", ks.Name, s) 149 } 150 151 func QualifiedStrings(ks *vindexes.Keyspace, ss []string) []string { 152 add, collect := collectSortedUniqueStrings() 153 for _, s := range ss { 154 add(QualifiedString(ks, s)) 155 } 156 return collect() 157 } 158 159 func QualifiedTableName(ks *vindexes.Keyspace, t sqlparser.TableName) string { 160 return QualifiedIdentifier(ks, t.Name) 161 } 162 163 func QualifiedTableNames(ks *vindexes.Keyspace, ts []sqlparser.TableName) []string { 164 add, collect := collectSortedUniqueStrings() 165 for _, t := range ts { 166 add(QualifiedTableName(ks, t)) 167 } 168 return collect() 169 } 170 171 func QualifiedTables(ks *vindexes.Keyspace, vts []*vindexes.Table) []string { 172 add, collect := collectSortedUniqueStrings() 173 for _, vt := range vts { 174 add(QualifiedIdentifier(ks, vt.Name)) 175 } 176 return collect() 177 } 178 179 func SingleQualifiedIdentifier(ks *vindexes.Keyspace, i sqlparser.IdentifierCS) []string { 180 return SingleQualifiedString(ks, i.String()) 181 } 182 183 func SingleQualifiedString(ks *vindexes.Keyspace, s string) []string { 184 return []string{QualifiedString(ks, s)} 185 } 186 187 func SingleQualifiedTableName(ks *vindexes.Keyspace, t sqlparser.TableName) []string { 188 return SingleQualifiedIdentifier(ks, t.Name) 189 } 190 191 func collectSortedUniqueStrings() (add func(string), collect func() []string) { 192 uniq := make(map[string]any) 193 add = func(v string) { 194 uniq[v] = nil 195 } 196 collect = func() []string { 197 sorted := make([]string, 0, len(uniq)) 198 for v := range uniq { 199 sorted = append(sorted, v) 200 } 201 sort.Strings(sorted) 202 return sorted 203 } 204 205 return add, collect 206 }