github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/s3select/sql/evaluate.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package sql
    19  
    20  import (
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"math"
    25  	"strings"
    26  
    27  	"github.com/bcicen/jstream"
    28  	"github.com/minio/simdjson-go"
    29  )
    30  
    31  var (
    32  	errInvalidASTNode    = errors.New("invalid AST Node")
    33  	errExpectedBool      = errors.New("expected bool")
    34  	errLikeNonStrArg     = errors.New("LIKE clause requires string arguments")
    35  	errLikeInvalidEscape = errors.New("LIKE clause has invalid ESCAPE character")
    36  	errNotImplemented    = errors.New("not implemented")
    37  )
    38  
    39  // AST Node Evaluation functions
    40  //
    41  // During evaluation, the query is known to be valid, as analysis is
    42  // complete. The only errors possible are due to value type
    43  // mismatches, etc.
    44  //
    45  // If an aggregation node is present as a descendant (when
    46  // e.prop.isAggregation is true), we call evalNode on all child nodes,
    47  // check for errors, but do not perform any combining of the results
    48  // of child nodes. The final result row is returned after all rows are
    49  // processed, and the `getAggregate` function is called.
    50  
    51  func (e *AliasedExpression) evalNode(r Record, tableAlias string) (*Value, error) {
    52  	return e.Expression.evalNode(r, tableAlias)
    53  }
    54  
    55  func (e *Expression) evalNode(r Record, tableAlias string) (*Value, error) {
    56  	if len(e.And) == 1 {
    57  		// In this case, result is not required to be boolean
    58  		// type.
    59  		return e.And[0].evalNode(r, tableAlias)
    60  	}
    61  
    62  	// Compute OR of conditions
    63  	result := false
    64  	for _, ex := range e.And {
    65  		res, err := ex.evalNode(r, tableAlias)
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  		b, ok := res.ToBool()
    70  		if !ok {
    71  			return nil, errExpectedBool
    72  		}
    73  		if b {
    74  			return FromBool(true), nil
    75  		}
    76  		result = result || b
    77  	}
    78  	return FromBool(result), nil
    79  }
    80  
    81  func (e *AndCondition) evalNode(r Record, tableAlias string) (*Value, error) {
    82  	if len(e.Condition) == 1 {
    83  		// In this case, result does not have to be boolean
    84  		return e.Condition[0].evalNode(r, tableAlias)
    85  	}
    86  
    87  	// Compute AND of conditions
    88  	result := true
    89  	for _, ex := range e.Condition {
    90  		res, err := ex.evalNode(r, tableAlias)
    91  		if err != nil {
    92  			return nil, err
    93  		}
    94  		b, ok := res.ToBool()
    95  		if !ok {
    96  			return nil, errExpectedBool
    97  		}
    98  		if !b {
    99  			return FromBool(false), nil
   100  		}
   101  		result = result && b
   102  	}
   103  	return FromBool(result), nil
   104  }
   105  
   106  func (e *Condition) evalNode(r Record, tableAlias string) (*Value, error) {
   107  	if e.Operand != nil {
   108  		// In this case, result does not have to be boolean
   109  		return e.Operand.evalNode(r, tableAlias)
   110  	}
   111  
   112  	// Compute NOT of condition
   113  	res, err := e.Not.evalNode(r, tableAlias)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	b, ok := res.ToBool()
   118  	if !ok {
   119  		return nil, errExpectedBool
   120  	}
   121  	return FromBool(!b), nil
   122  }
   123  
   124  func (e *ConditionOperand) evalNode(r Record, tableAlias string) (*Value, error) {
   125  	opVal, opErr := e.Operand.evalNode(r, tableAlias)
   126  	if opErr != nil || e.ConditionRHS == nil {
   127  		return opVal, opErr
   128  	}
   129  
   130  	// Need to evaluate the ConditionRHS
   131  	switch {
   132  	case e.ConditionRHS.Compare != nil:
   133  		cmpRight, cmpRErr := e.ConditionRHS.Compare.Operand.evalNode(r, tableAlias)
   134  		if cmpRErr != nil {
   135  			return nil, cmpRErr
   136  		}
   137  
   138  		b, err := opVal.compareOp(strings.ToUpper(e.ConditionRHS.Compare.Operator), cmpRight)
   139  		return FromBool(b), err
   140  
   141  	case e.ConditionRHS.Between != nil:
   142  		return e.ConditionRHS.Between.evalBetweenNode(r, opVal, tableAlias)
   143  
   144  	case e.ConditionRHS.Like != nil:
   145  		return e.ConditionRHS.Like.evalLikeNode(r, opVal, tableAlias)
   146  
   147  	case e.ConditionRHS.In != nil:
   148  		return e.ConditionRHS.In.evalInNode(r, opVal, tableAlias)
   149  
   150  	default:
   151  		return nil, errInvalidASTNode
   152  	}
   153  }
   154  
   155  func (e *Between) evalBetweenNode(r Record, arg *Value, tableAlias string) (*Value, error) {
   156  	stVal, stErr := e.Start.evalNode(r, tableAlias)
   157  	if stErr != nil {
   158  		return nil, stErr
   159  	}
   160  
   161  	endVal, endErr := e.End.evalNode(r, tableAlias)
   162  	if endErr != nil {
   163  		return nil, endErr
   164  	}
   165  
   166  	part1, err1 := stVal.compareOp(opLte, arg)
   167  	if err1 != nil {
   168  		return nil, err1
   169  	}
   170  
   171  	part2, err2 := arg.compareOp(opLte, endVal)
   172  	if err2 != nil {
   173  		return nil, err2
   174  	}
   175  
   176  	result := part1 && part2
   177  	if e.Not {
   178  		result = !result
   179  	}
   180  
   181  	return FromBool(result), nil
   182  }
   183  
   184  func (e *Like) evalLikeNode(r Record, arg *Value, tableAlias string) (*Value, error) {
   185  	inferTypeAsString(arg)
   186  
   187  	s, ok := arg.ToString()
   188  	if !ok {
   189  		err := errLikeNonStrArg
   190  		return nil, errLikeInvalidInputs(err)
   191  	}
   192  
   193  	pattern, err1 := e.Pattern.evalNode(r, tableAlias)
   194  	if err1 != nil {
   195  		return nil, err1
   196  	}
   197  
   198  	// Infer pattern as string (in case it is untyped)
   199  	inferTypeAsString(pattern)
   200  
   201  	patternStr, ok := pattern.ToString()
   202  	if !ok {
   203  		err := errLikeNonStrArg
   204  		return nil, errLikeInvalidInputs(err)
   205  	}
   206  
   207  	escape := runeZero
   208  	if e.EscapeChar != nil {
   209  		escapeVal, err2 := e.EscapeChar.evalNode(r, tableAlias)
   210  		if err2 != nil {
   211  			return nil, err2
   212  		}
   213  
   214  		inferTypeAsString(escapeVal)
   215  
   216  		escapeStr, ok := escapeVal.ToString()
   217  		if !ok {
   218  			err := errLikeNonStrArg
   219  			return nil, errLikeInvalidInputs(err)
   220  		}
   221  
   222  		if len([]rune(escapeStr)) > 1 {
   223  			err := errLikeInvalidEscape
   224  			return nil, errLikeInvalidInputs(err)
   225  		}
   226  	}
   227  
   228  	matchResult, err := evalSQLLike(s, patternStr, escape)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  
   233  	if e.Not {
   234  		matchResult = !matchResult
   235  	}
   236  
   237  	return FromBool(matchResult), nil
   238  }
   239  
   240  func (e *ListExpr) evalNode(r Record, tableAlias string) (*Value, error) {
   241  	res := make([]Value, len(e.Elements))
   242  	if len(e.Elements) == 1 {
   243  		// If length 1, treat as single value.
   244  		return e.Elements[0].evalNode(r, tableAlias)
   245  	}
   246  	for i, elt := range e.Elements {
   247  		v, err := elt.evalNode(r, tableAlias)
   248  		if err != nil {
   249  			return nil, err
   250  		}
   251  		res[i] = *v
   252  	}
   253  	return FromArray(res), nil
   254  }
   255  
   256  const floatCmpTolerance = 0.000001
   257  
   258  func (e *In) evalInNode(r Record, lhs *Value, tableAlias string) (*Value, error) {
   259  	// Compare two values in terms of in-ness.
   260  	var cmp func(a, b Value) bool
   261  	cmp = func(a, b Value) bool {
   262  		// Convert if needed.
   263  		inferTypesForCmp(&a, &b)
   264  
   265  		if a.Equals(b) {
   266  			return true
   267  		}
   268  
   269  		// If elements, compare each.
   270  		aA, aOK := a.ToArray()
   271  		bA, bOK := b.ToArray()
   272  		if aOK && bOK {
   273  			if len(aA) != len(bA) {
   274  				return false
   275  			}
   276  			for i := range aA {
   277  				if !cmp(aA[i], bA[i]) {
   278  					return false
   279  				}
   280  			}
   281  			return true
   282  		}
   283  		// Try as numbers
   284  		aF, aOK := a.ToFloat()
   285  		bF, bOK := b.ToFloat()
   286  
   287  		diff := math.Abs(aF - bF)
   288  		return aOK && bOK && diff < floatCmpTolerance
   289  	}
   290  
   291  	var rhs Value
   292  	var err error
   293  	var eltVal *Value
   294  	switch {
   295  	case e.JPathExpr != nil:
   296  		eltVal, err = e.JPathExpr.evalNode(r, tableAlias)
   297  		if err != nil {
   298  			return nil, err
   299  		}
   300  	case e.ListExpr != nil:
   301  		eltVal, err = e.ListExpr.evalNode(r, tableAlias)
   302  		if err != nil {
   303  			return nil, err
   304  		}
   305  	default:
   306  		return nil, errInvalidASTNode
   307  	}
   308  	rhs = *eltVal
   309  
   310  	// If RHS is array compare each element.
   311  	if arr, ok := rhs.ToArray(); ok {
   312  		for _, element := range arr {
   313  			// If we have an array we are on the wrong level.
   314  			if cmp(element, *lhs) {
   315  				return FromBool(true), nil
   316  			}
   317  		}
   318  		return FromBool(false), nil
   319  	}
   320  
   321  	return FromBool(cmp(rhs, *lhs)), nil
   322  }
   323  
   324  func (e *Operand) evalNode(r Record, tableAlias string) (*Value, error) {
   325  	lval, lerr := e.Left.evalNode(r, tableAlias)
   326  	if lerr != nil || len(e.Right) == 0 {
   327  		return lval, lerr
   328  	}
   329  
   330  	// Process remaining child nodes - result must be
   331  	// numeric. This AST node is for terms separated by + or -
   332  	// symbols.
   333  	for _, rightTerm := range e.Right {
   334  		op := rightTerm.Op
   335  		rval, rerr := rightTerm.Right.evalNode(r, tableAlias)
   336  		if rerr != nil {
   337  			return nil, rerr
   338  		}
   339  		err := lval.arithOp(op, rval)
   340  		if err != nil {
   341  			return nil, err
   342  		}
   343  	}
   344  	return lval, nil
   345  }
   346  
   347  func (e *MultOp) evalNode(r Record, tableAlias string) (*Value, error) {
   348  	lval, lerr := e.Left.evalNode(r, tableAlias)
   349  	if lerr != nil || len(e.Right) == 0 {
   350  		return lval, lerr
   351  	}
   352  
   353  	// Process other child nodes - result must be numeric. This
   354  	// AST node is for terms separated by *, / or % symbols.
   355  	for _, rightTerm := range e.Right {
   356  		op := rightTerm.Op
   357  		rval, rerr := rightTerm.Right.evalNode(r, tableAlias)
   358  		if rerr != nil {
   359  			return nil, rerr
   360  		}
   361  
   362  		err := lval.arithOp(op, rval)
   363  		if err != nil {
   364  			return nil, err
   365  		}
   366  	}
   367  	return lval, nil
   368  }
   369  
   370  func (e *UnaryTerm) evalNode(r Record, tableAlias string) (*Value, error) {
   371  	if e.Negated == nil {
   372  		return e.Primary.evalNode(r, tableAlias)
   373  	}
   374  
   375  	v, err := e.Negated.Term.evalNode(r, tableAlias)
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  
   380  	inferTypeForArithOp(v)
   381  	v.negate()
   382  	if v.isNumeric() {
   383  		return v, nil
   384  	}
   385  	return nil, errArithMismatchedTypes
   386  }
   387  
   388  func (e *JSONPath) evalNode(r Record, tableAlias string) (*Value, error) {
   389  	alias := tableAlias
   390  	if tableAlias == "" {
   391  		alias = baseTableName
   392  	}
   393  	pathExpr := e.StripTableAlias(alias)
   394  	_, rawVal := r.Raw()
   395  	switch rowVal := rawVal.(type) {
   396  	case jstream.KVS, simdjson.Object:
   397  		if len(pathExpr) == 0 {
   398  			pathExpr = []*JSONPathElement{{Key: &ObjectKey{ID: e.BaseKey}}}
   399  		}
   400  
   401  		result, _, err := jsonpathEval(pathExpr, rowVal)
   402  		if err != nil {
   403  			return nil, err
   404  		}
   405  
   406  		return jsonToValue(result)
   407  	default:
   408  		if pathExpr[len(pathExpr)-1].Key == nil {
   409  			return nil, errInvalidKeypath
   410  		}
   411  		return r.Get(pathExpr[len(pathExpr)-1].Key.keyString())
   412  	}
   413  }
   414  
   415  // jsonToValue will convert the json value to an internal value.
   416  func jsonToValue(result interface{}) (*Value, error) {
   417  	switch rval := result.(type) {
   418  	case string:
   419  		return FromString(rval), nil
   420  	case float64:
   421  		return FromFloat(rval), nil
   422  	case int64:
   423  		return FromInt(rval), nil
   424  	case uint64:
   425  		if rval <= math.MaxInt64 {
   426  			return FromInt(int64(rval)), nil
   427  		}
   428  		return FromFloat(float64(rval)), nil
   429  	case bool:
   430  		return FromBool(rval), nil
   431  	case jstream.KVS:
   432  		bs, err := json.Marshal(result)
   433  		if err != nil {
   434  			return nil, err
   435  		}
   436  		return FromBytes(bs), nil
   437  	case []interface{}:
   438  		dst := make([]Value, len(rval))
   439  		for i := range rval {
   440  			v, err := jsonToValue(rval[i])
   441  			if err != nil {
   442  				return nil, err
   443  			}
   444  			dst[i] = *v
   445  		}
   446  		return FromArray(dst), nil
   447  	case simdjson.Object:
   448  		o := rval
   449  		elems, err := o.Parse(nil)
   450  		if err != nil {
   451  			return nil, err
   452  		}
   453  		bs, err := elems.MarshalJSON()
   454  		if err != nil {
   455  			return nil, err
   456  		}
   457  		return FromBytes(bs), nil
   458  	case []Value:
   459  		return FromArray(rval), nil
   460  	case nil:
   461  		return FromNull(), nil
   462  	case Missing:
   463  		return FromMissing(), nil
   464  	}
   465  	return nil, fmt.Errorf("Unhandled value type: %T", result)
   466  }
   467  
   468  func (e *PrimaryTerm) evalNode(r Record, tableAlias string) (res *Value, err error) {
   469  	switch {
   470  	case e.Value != nil:
   471  		return e.Value.evalNode(r)
   472  	case e.JPathExpr != nil:
   473  		return e.JPathExpr.evalNode(r, tableAlias)
   474  	case e.ListExpr != nil:
   475  		return e.ListExpr.evalNode(r, tableAlias)
   476  	case e.SubExpression != nil:
   477  		return e.SubExpression.evalNode(r, tableAlias)
   478  	case e.FuncCall != nil:
   479  		return e.FuncCall.evalNode(r, tableAlias)
   480  	}
   481  	return nil, errInvalidASTNode
   482  }
   483  
   484  func (e *FuncExpr) evalNode(r Record, tableAlias string) (res *Value, err error) {
   485  	switch e.getFunctionName() {
   486  	case aggFnCount, aggFnAvg, aggFnMax, aggFnMin, aggFnSum:
   487  		return e.getAggregate()
   488  	default:
   489  		return e.evalSQLFnNode(r, tableAlias)
   490  	}
   491  }
   492  
   493  // evalNode on a literal value is independent of the node being an
   494  // aggregation or a row function - it always returns a value.
   495  func (e *LitValue) evalNode(_ Record) (res *Value, err error) {
   496  	switch {
   497  	case e.Int != nil:
   498  		if *e.Int < math.MaxInt64 && *e.Int > math.MinInt64 {
   499  			return FromInt(int64(*e.Int)), nil
   500  		}
   501  		return FromFloat(*e.Int), nil
   502  	case e.Float != nil:
   503  		return FromFloat(*e.Float), nil
   504  	case e.String != nil:
   505  		return FromString(string(*e.String)), nil
   506  	case e.Boolean != nil:
   507  		return FromBool(bool(*e.Boolean)), nil
   508  	case e.Missing:
   509  		return FromMissing(), nil
   510  	}
   511  	return FromNull(), nil
   512  }