github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/optgen/exprgen/expr_gen.go (about)

     1  // Copyright 2019 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 exprgen
    12  
    13  import (
    14  	"fmt"
    15  	"io"
    16  	"reflect"
    17  	"strings"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/opt/norm"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/opt/optgen/lang"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/opt/ordering"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/opt/xform"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    29  	"github.com/cockroachdb/errors"
    30  )
    31  
    32  // Build generates an expression from an optgen string (the kind of expression
    33  // that would show up in the replace side of a rule).
    34  //
    35  // For example, if the input is "(Eq (Const 1) (Const 2))", the output is the
    36  // corresponding expression tree:
    37  //   eq [type=bool]
    38  //    ├── const: 1 [type=int]
    39  //    └── const: 2 [type=int]
    40  //
    41  // There are some peculiarities compared to the usual opt-gen replace syntax:
    42  //
    43  //  - Filters are specified as simply [ <condition> ... ]; no FiltersItem is
    44  //    necessary.
    45  //
    46  //  - Various implicit conversions are allowed for convenience, e.g. list of
    47  //    columns to ColList/ColSet.
    48  //
    49  //  - Operation privates (e.g. ScanPrivate) are specified as lists of fields
    50  //    of the form [ (FiledName <value>) ]. For example:
    51  //      [ (Table "abc") (Index "abc@ab") (Cols "a,b") ]
    52  //    Implicit conversions are allowed here for column lists, orderings, etc.
    53  //
    54  //  - A Root custom function is used to set the physical properties of the root.
    55  //    Setting the physical properties (in particular the presentation) is always
    56  //    necessary for the plan to be run via PREPARE .. AS OPT PLAN '..'.
    57  //
    58  // Some examples of valid inputs:
    59  //    (Tuple [ (True) (False) ] "tuple{bool, bool}" )
    60  //
    61  //    (Root
    62  //      (Scan [ (Table "abc") (Index "abc@ab") (Cols "a,b") ])
    63  //      (Presentation "a,b")
    64  //      (OrderingChoice "+a,+b")
    65  //    )
    66  //
    67  //    (Select
    68  //      (Scan [ (Table "abc") (Cols "a,b,c") ])
    69  //      [ (Eq (Var "a") (Const 1)) ]
    70  //    )
    71  //
    72  // For more examples, see the various testdata/ files.
    73  //
    74  func Build(catalog cat.Catalog, factory *norm.Factory, input string) (_ opt.Expr, err error) {
    75  	defer func() {
    76  		if r := recover(); r != nil {
    77  			if e, ok := r.(exprGenErr); ok {
    78  				err = e.error
    79  			} else {
    80  				panic(r)
    81  			}
    82  		}
    83  	}()
    84  
    85  	eg := exprGen{
    86  		customFuncs: customFuncs{
    87  			f:   factory,
    88  			mem: factory.Memo(),
    89  			cat: catalog,
    90  		},
    91  		coster: xform.MakeDefaultCoster(factory.Memo()),
    92  	}
    93  
    94  	// To create a valid optgen "file", we create a rule with a bogus match.
    95  	contents := "[FakeRule] (True) => " + input
    96  	parsed := eg.parse(contents)
    97  	result := eg.eval(parsed.Rules[0].Replace)
    98  
    99  	var expr opt.Expr
   100  	required := physical.MinRequired
   101  	if root, ok := result.(*rootSentinel); ok {
   102  		expr = root.expr
   103  		required = root.required
   104  	} else {
   105  		expr = result.(opt.Expr)
   106  	}
   107  	eg.populateBestProps(expr, required)
   108  	if rel, ok := expr.(memo.RelExpr); ok {
   109  		eg.mem.SetRoot(rel, required)
   110  	}
   111  	return expr, nil
   112  }
   113  
   114  type exprGen struct {
   115  	customFuncs
   116  
   117  	coster xform.Coster
   118  }
   119  
   120  type exprGenErr struct {
   121  	error
   122  }
   123  
   124  func errorf(format string, a ...interface{}) error {
   125  	return exprGenErr{fmt.Errorf(format, a...)}
   126  }
   127  
   128  func wrapf(err error, format string, a ...interface{}) error {
   129  	return exprGenErr{errors.WrapWithDepthf(1, err, format, a...)}
   130  }
   131  
   132  // Parses the input (with replace-side rule syntax) into an optgen expression
   133  // tree.
   134  func (eg *exprGen) parse(contents string) *lang.RootExpr {
   135  	p := lang.NewParser("fake.opt")
   136  	p.SetFileResolver(func(name string) (io.Reader, error) {
   137  		if name == "fake.opt" {
   138  			return strings.NewReader(contents), nil
   139  		}
   140  		return nil, fmt.Errorf("unknown file '%s'", name)
   141  	})
   142  	parsed := p.Parse()
   143  	if parsed == nil {
   144  		errStr := "Errors during parsing:\n"
   145  		for _, err := range p.Errors() {
   146  			errStr = fmt.Sprintf("%s%s\n", errStr, err.Error())
   147  		}
   148  		panic(errorf("%s", errStr))
   149  	}
   150  	return parsed
   151  }
   152  
   153  // Evaluates the corresponding expression.
   154  func (eg *exprGen) eval(expr lang.Expr) interface{} {
   155  	switch expr := expr.(type) {
   156  	case *lang.FuncExpr:
   157  		if expr.HasDynamicName() {
   158  			panic(errorf("dynamic functions not supported: %s", expr))
   159  		}
   160  
   161  		name := expr.SingleName()
   162  		// Search for a factory function.
   163  		method := reflect.ValueOf(eg.f).MethodByName("Construct" + name)
   164  		if !method.IsValid() {
   165  			// Search for a custom function.
   166  			method = reflect.ValueOf(&eg.customFuncs).MethodByName(name)
   167  			if !method.IsValid() {
   168  				panic(errorf("unknown operator or function %s", name))
   169  			}
   170  		}
   171  		return eg.call(name, method, expr.Args)
   172  
   173  	case *lang.ListExpr:
   174  		// Return a list expression as []interface{}.
   175  		list := make([]interface{}, len(expr.Items))
   176  		for i, e := range expr.Items {
   177  			list[i] = eg.eval(e)
   178  		}
   179  		return list
   180  
   181  	case *lang.NumberExpr:
   182  		return tree.NewDInt(tree.DInt(*expr))
   183  
   184  	case *lang.StringExpr:
   185  		return string(*expr)
   186  
   187  	default:
   188  		panic(errorf("unsupported expression %s: %v", expr.Op(), expr))
   189  	}
   190  }
   191  
   192  // Calls a function (custom function or factory method) with the given
   193  // arguments. Various implicit conversions are allowed.
   194  func (eg *exprGen) call(name string, method reflect.Value, args lang.SliceExpr) interface{} {
   195  	fnTyp := method.Type()
   196  	if fnTyp.NumIn() != len(args) {
   197  		panic(errorf("%s expects %d arguments", name, fnTyp.NumIn()))
   198  	}
   199  	argVals := make([]reflect.Value, len(args))
   200  	for i := range args {
   201  		desiredType := fnTyp.In(i)
   202  
   203  		// Special case for privates.
   204  		if desiredType.Kind() == reflect.Ptr && desiredType.Elem().Kind() == reflect.Struct &&
   205  			strings.HasSuffix(desiredType.Elem().Name(), "Private") {
   206  			argVals[i] = reflect.ValueOf(eg.evalPrivate(desiredType.Elem(), args[i]))
   207  			continue
   208  		}
   209  
   210  		arg := eg.eval(args[i])
   211  		converted := eg.castToDesiredType(arg, desiredType)
   212  		if converted == nil {
   213  			panic(errorf("%s: using %T as type %s", name, arg, desiredType))
   214  		}
   215  		argVals[i] = reflect.ValueOf(converted)
   216  	}
   217  	return method.Call(argVals)[0].Interface()
   218  }
   219  
   220  // castToDesiredType tries to convert the given argument to a value of the given
   221  // type. Returns nil if conversion was not possible.
   222  func (eg *exprGen) castToDesiredType(arg interface{}, desiredType reflect.Type) interface{} {
   223  	actualType := reflect.TypeOf(arg)
   224  	if actualType.AssignableTo(desiredType) {
   225  		return arg
   226  	}
   227  
   228  	if slice, ok := arg.([]interface{}); ok {
   229  		// Special case for converting slice of ColumnIDs to a ColSet.
   230  		if desiredType == reflect.TypeOf(opt.ColSet{}) {
   231  			var set opt.ColSet
   232  			for i := range slice {
   233  				col, ok := slice[i].(opt.ColumnID)
   234  				if !ok {
   235  					return nil
   236  				}
   237  				set.Add(col)
   238  			}
   239  			return set
   240  		}
   241  
   242  		if desiredType.Kind() != reflect.Slice {
   243  			return nil
   244  		}
   245  
   246  		// See if we can convert all elements to the desired slice element type.
   247  		converted := convertSlice(slice, desiredType, func(v interface{}) interface{} {
   248  			if val := reflect.ValueOf(v); val.Type().AssignableTo(desiredType.Elem()) {
   249  				return val.Convert(desiredType.Elem()).Interface()
   250  			}
   251  			return nil
   252  		})
   253  		if converted != nil {
   254  			return converted
   255  		}
   256  
   257  		// Special case for converting slice of values implementing ScalarExpr to a
   258  		// FiltersExpr.
   259  		if desiredType == reflect.TypeOf(memo.FiltersExpr{}) {
   260  			converted := convertSlice(slice, desiredType, func(v interface{}) interface{} {
   261  				expr, ok := v.(opt.ScalarExpr)
   262  				if !ok {
   263  					return nil
   264  				}
   265  				return eg.f.ConstructFiltersItem(expr)
   266  			})
   267  			if converted != nil {
   268  				return converted
   269  			}
   270  		}
   271  	}
   272  
   273  	if i, ok := arg.(*tree.DInt); ok {
   274  		if desiredType == reflect.TypeOf(memo.ScanLimit(0)) {
   275  			return memo.MakeScanLimit(int64(*i), false)
   276  		}
   277  	}
   278  
   279  	if str, ok := arg.(string); ok {
   280  		// String to type.
   281  		if desiredType == reflect.TypeOf((*types.T)(nil)) {
   282  			typ, err := ParseType(str)
   283  			if err != nil {
   284  				panic(exprGenErr{err})
   285  			}
   286  			return typ
   287  		}
   288  
   289  		// String to Ordering.
   290  		if desiredType == reflect.TypeOf(opt.Ordering{}) {
   291  			return eg.Ordering(str)
   292  		}
   293  
   294  		// String to OrderingChoice.
   295  		if desiredType == reflect.TypeOf(physical.OrderingChoice{}) {
   296  			return eg.OrderingChoice(str)
   297  		}
   298  
   299  		// String to ColList.
   300  		if desiredType == reflect.TypeOf(opt.ColList{}) {
   301  			return eg.ColList(str)
   302  		}
   303  
   304  		// String to ColSet.
   305  		if desiredType == reflect.TypeOf(opt.ColSet{}) {
   306  			return eg.ColSet(str)
   307  		}
   308  
   309  		// String to ExplainOptions.
   310  		if desiredType == reflect.TypeOf(tree.ExplainOptions{}) {
   311  			return eg.ExplainOptions(str)
   312  		}
   313  
   314  		// String to bool.
   315  		if desiredType == reflect.TypeOf(true) {
   316  			switch str {
   317  			case "true":
   318  				return true
   319  			case "false":
   320  				return false
   321  			default:
   322  				panic(errorf("invalid boolean value \"%s\" (expected \"true\" or \"false\")", str))
   323  			}
   324  		}
   325  	}
   326  	return nil
   327  }
   328  
   329  // convertSlice tries to create a slice of the given type; each element is the
   330  // result of calling mapFn on the input slice element.
   331  //
   332  // If mapFn returns nil for any element, convertSlice also returns nil.
   333  func convertSlice(
   334  	slice []interface{}, toType reflect.Type, mapFn func(v interface{}) interface{},
   335  ) interface{} {
   336  	res := reflect.MakeSlice(toType, len(slice), len(slice))
   337  
   338  	for i, v := range slice {
   339  		val := mapFn(v)
   340  		if val == nil {
   341  			return nil
   342  		}
   343  		res.Index(i).Set(reflect.ValueOf(val))
   344  	}
   345  	return res.Interface()
   346  }
   347  
   348  // populateBestProps sets the physical properties and costs of the expressions
   349  // in the tree. Returns the cost of the expression tree.
   350  func (eg *exprGen) populateBestProps(expr opt.Expr, required *physical.Required) memo.Cost {
   351  	rel, _ := expr.(memo.RelExpr)
   352  	if rel != nil {
   353  		if !xform.CanProvidePhysicalProps(rel, required) {
   354  			panic(errorf("operator %s cannot provide required props %s", rel.Op(), required))
   355  		}
   356  	}
   357  
   358  	var cost memo.Cost
   359  	for i, n := 0, expr.ChildCount(); i < n; i++ {
   360  		var childProps *physical.Required
   361  		if rel != nil {
   362  			childProps = xform.BuildChildPhysicalProps(eg.mem, rel, i, required)
   363  		} else {
   364  			childProps = xform.BuildChildPhysicalPropsScalar(eg.mem, expr, i)
   365  		}
   366  		cost += eg.populateBestProps(expr.Child(i), childProps)
   367  	}
   368  
   369  	if rel != nil {
   370  		provided := &physical.Provided{}
   371  		// BuildProvided relies on ProvidedPhysical() being set in the children, so
   372  		// it must run after the recursive calls on the children.
   373  		provided.Ordering = ordering.BuildProvided(rel, &required.Ordering)
   374  
   375  		cost += eg.coster.ComputeCost(rel, required)
   376  		eg.mem.SetBestProps(rel, required, provided, cost)
   377  	}
   378  	return cost
   379  }