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 }