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  }