github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/s3select/sql/value.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 "reflect" 26 "strconv" 27 "strings" 28 "time" 29 "unicode/utf8" 30 ) 31 32 var ( 33 errArithMismatchedTypes = errors.New("cannot perform arithmetic on mismatched types") 34 errArithInvalidOperator = errors.New("invalid arithmetic operator") 35 errArithDivideByZero = errors.New("cannot divide by 0") 36 37 errCmpMismatchedTypes = errors.New("cannot compare values of different types") 38 errCmpInvalidBoolOperator = errors.New("invalid comparison operator for boolean arguments") 39 ) 40 41 // Value represents a value of restricted type reduced from an 42 // expression represented by an ASTNode. Only one of the fields is 43 // non-nil. 44 // 45 // In cases where we are fetching data from a data source (like csv), 46 // the type may not be determined yet. In these cases, a byte-slice is 47 // used. 48 type Value struct { 49 value interface{} 50 } 51 52 // Missing is used to indicate a non-existing value. 53 type Missing struct{} 54 55 // MarshalJSON provides json marshaling of values. 56 func (v Value) MarshalJSON() ([]byte, error) { 57 if b, ok := v.ToBytes(); ok { 58 return b, nil 59 } 60 return json.Marshal(v.value) 61 } 62 63 // GetTypeString returns a string representation for vType 64 func (v Value) GetTypeString() string { 65 switch v.value.(type) { 66 case nil: 67 return "NULL" 68 case bool: 69 return "BOOL" 70 case string: 71 return "STRING" 72 case int64: 73 return "INT" 74 case float64: 75 return "FLOAT" 76 case time.Time: 77 return "TIMESTAMP" 78 case []byte: 79 return "BYTES" 80 case []Value: 81 return "ARRAY" 82 case Missing: 83 return "MISSING" 84 } 85 return "--" 86 } 87 88 // Repr returns a string representation of value. 89 func (v Value) Repr() string { 90 switch x := v.value.(type) { 91 case nil: 92 return ":NULL" 93 case bool, int64, float64: 94 return fmt.Sprintf("%v:%s", v.value, v.GetTypeString()) 95 case time.Time: 96 return fmt.Sprintf("%s:TIMESTAMP", x) 97 case string: 98 return fmt.Sprintf("\"%s\":%s", x, v.GetTypeString()) 99 case []byte: 100 return fmt.Sprintf("\"%s\":BYTES", string(x)) 101 case []Value: 102 var s strings.Builder 103 s.WriteByte('[') 104 for i, v := range x { 105 s.WriteString(v.Repr()) 106 if i < len(x)-1 { 107 s.WriteByte(',') 108 } 109 } 110 s.WriteString("]:ARRAY") 111 return s.String() 112 case Missing: 113 return ":MISSING" 114 default: 115 return fmt.Sprintf("%v:INVALID", v.value) 116 } 117 } 118 119 // FromFloat creates a Value from a number 120 func FromFloat(f float64) *Value { 121 return &Value{value: f} 122 } 123 124 // FromInt creates a Value from an int 125 func FromInt(f int64) *Value { 126 return &Value{value: f} 127 } 128 129 // FromString creates a Value from a string 130 func FromString(str string) *Value { 131 return &Value{value: str} 132 } 133 134 // FromBool creates a Value from a bool 135 func FromBool(b bool) *Value { 136 return &Value{value: b} 137 } 138 139 // FromTimestamp creates a Value from a timestamp 140 func FromTimestamp(t time.Time) *Value { 141 return &Value{value: t} 142 } 143 144 // FromNull creates a Value with Null value 145 func FromNull() *Value { 146 return &Value{value: nil} 147 } 148 149 // FromMissing creates a Value with Missing value 150 func FromMissing() *Value { 151 return &Value{value: Missing{}} 152 } 153 154 // FromBytes creates a Value from a []byte 155 func FromBytes(b []byte) *Value { 156 return &Value{value: b} 157 } 158 159 // FromArray creates a Value from an array of values. 160 func FromArray(a []Value) *Value { 161 return &Value{value: a} 162 } 163 164 // ToFloat works for int and float values 165 func (v Value) ToFloat() (val float64, ok bool) { 166 switch x := v.value.(type) { 167 case float64: 168 return x, true 169 case int64: 170 return float64(x), true 171 } 172 return 0, false 173 } 174 175 // ToInt returns the value if int. 176 func (v Value) ToInt() (val int64, ok bool) { 177 val, ok = v.value.(int64) 178 return 179 } 180 181 // ToString returns the value if string. 182 func (v Value) ToString() (val string, ok bool) { 183 val, ok = v.value.(string) 184 return 185 } 186 187 // Equals returns whether the values strictly match. 188 // Both type and value must match. 189 func (v Value) Equals(b Value) (ok bool) { 190 if !v.SameTypeAs(b) { 191 return false 192 } 193 return reflect.DeepEqual(v.value, b.value) 194 } 195 196 // SameTypeAs return whether the two types are strictly the same. 197 func (v Value) SameTypeAs(b Value) (ok bool) { 198 switch v.value.(type) { 199 case bool: 200 _, ok = b.value.(bool) 201 case string: 202 _, ok = b.value.(string) 203 case int64: 204 _, ok = b.value.(int64) 205 case float64: 206 _, ok = b.value.(float64) 207 case time.Time: 208 _, ok = b.value.(time.Time) 209 case []byte: 210 _, ok = b.value.([]byte) 211 case []Value: 212 _, ok = b.value.([]Value) 213 default: 214 ok = reflect.TypeOf(v.value) == reflect.TypeOf(b.value) 215 } 216 return ok 217 } 218 219 // ToBool returns the bool value; second return value refers to if the bool 220 // conversion succeeded. 221 func (v Value) ToBool() (val bool, ok bool) { 222 val, ok = v.value.(bool) 223 return 224 } 225 226 // ToTimestamp returns the timestamp value if present. 227 func (v Value) ToTimestamp() (t time.Time, ok bool) { 228 t, ok = v.value.(time.Time) 229 return 230 } 231 232 // ToBytes returns the value if byte-slice. 233 func (v Value) ToBytes() (val []byte, ok bool) { 234 val, ok = v.value.([]byte) 235 return 236 } 237 238 // ToArray returns the value if it is a slice of values. 239 func (v Value) ToArray() (val []Value, ok bool) { 240 val, ok = v.value.([]Value) 241 return 242 } 243 244 // IsNull - checks if value is missing. 245 func (v Value) IsNull() bool { 246 //nolint:gocritic 247 switch v.value.(type) { 248 case nil: 249 return true 250 } 251 return false 252 } 253 254 // IsMissing - checks if value is missing. 255 func (v Value) IsMissing() bool { 256 _, ok := v.value.(Missing) 257 return ok 258 } 259 260 // IsArray returns whether the value is an array. 261 func (v Value) IsArray() (ok bool) { 262 _, ok = v.value.([]Value) 263 return ok 264 } 265 266 func (v Value) isNumeric() bool { 267 //nolint:gocritic 268 switch v.value.(type) { 269 case int64, float64: 270 return true 271 } 272 return false 273 } 274 275 // setters used internally to mutate values 276 277 func (v *Value) setInt(i int64) { 278 v.value = i 279 } 280 281 func (v *Value) setFloat(f float64) { 282 v.value = f 283 } 284 285 func (v *Value) setString(s string) { 286 v.value = s 287 } 288 289 func (v *Value) setBool(b bool) { 290 v.value = b 291 } 292 293 func (v *Value) setTimestamp(t time.Time) { 294 v.value = t 295 } 296 297 func (v Value) String() string { 298 return fmt.Sprintf("%#v", v.value) 299 } 300 301 // CSVString - convert to string for CSV serialization 302 func (v Value) CSVString() string { 303 switch x := v.value.(type) { 304 case nil, Missing: 305 return "" 306 case bool: 307 if x { 308 return "true" 309 } 310 return "false" 311 case string: 312 return x 313 case int64: 314 return strconv.FormatInt(x, 10) 315 case float64: 316 return strconv.FormatFloat(x, 'g', -1, 64) 317 case time.Time: 318 return FormatSQLTimestamp(x) 319 case []byte: 320 return string(x) 321 case []Value: 322 b, _ := json.Marshal(x) 323 return string(b) 324 325 default: 326 return "CSV serialization not implemented for this type" 327 } 328 } 329 330 // negate negates a numeric value 331 func (v *Value) negate() { 332 switch x := v.value.(type) { 333 case float64: 334 v.value = -x 335 case int64: 336 v.value = -x 337 } 338 } 339 340 // Value comparison functions: we do not expose them outside the 341 // module. Logical operators "<", ">", ">=", "<=" work on strings and 342 // numbers. Equality operators "=", "!=" work on strings, 343 // numbers and booleans. 344 345 // Supported comparison operators 346 const ( 347 opLt = "<" 348 opLte = "<=" 349 opGt = ">" 350 opGte = ">=" 351 opEq = "=" 352 opIneq = "!=" 353 opIs = "IS" 354 opIsNot = "ISNOT" 355 ) 356 357 // InferBytesType will attempt to infer the data type of bytes. 358 // Will fail if value type is not bytes or it would result in invalid utf8. 359 // ORDER: int, float, bool, JSON (object or array), timestamp, string 360 // If the content is valid JSON, the type will still be bytes. 361 func (v *Value) InferBytesType() (err error) { 362 b, ok := v.ToBytes() 363 if !ok { 364 return fmt.Errorf("InferByteType: Input is not bytes, but %v", v.GetTypeString()) 365 } 366 367 // Check for numeric inference 368 if x, ok := v.bytesToInt(); ok { 369 v.setInt(x) 370 return nil 371 } 372 if x, ok := v.bytesToFloat(); ok { 373 v.setFloat(x) 374 return nil 375 } 376 if x, ok := v.bytesToBool(); ok { 377 v.setBool(x) 378 return nil 379 } 380 381 asString := strings.TrimSpace(v.bytesToString()) 382 if len(b) > 0 && 383 (strings.HasPrefix(asString, "{") || strings.HasPrefix(asString, "[")) { 384 return nil 385 } 386 387 if t, err := parseSQLTimestamp(asString); err == nil { 388 v.setTimestamp(t) 389 return nil 390 } 391 if !utf8.Valid(b) { 392 return errors.New("value is not valid utf-8") 393 } 394 // Fallback to string 395 v.setString(asString) 396 return 397 } 398 399 // When numeric types are compared, type promotions could happen. If 400 // values do not have types (e.g. when reading from CSV), for 401 // comparison operations, automatic type conversion happens by trying 402 // to check if the value is a number (first an integer, then a float), 403 // and falling back to string. 404 func (v *Value) compareOp(op string, a *Value) (res bool, err error) { 405 if !isValidComparisonOperator(op) { 406 return false, errArithInvalidOperator 407 } 408 switch op { 409 case opIs: 410 if a.IsNull() { 411 // Missing is null 412 return v.IsNull() || v.IsMissing(), nil 413 } 414 if a.IsMissing() { 415 return v.IsMissing(), nil 416 } 417 // Forward to Equal 418 op = opEq 419 case opIsNot: 420 if a.IsNull() { 421 // Missing is not null 422 return !v.IsNull() && !v.IsMissing(), nil 423 } 424 if a.IsMissing() { 425 return !v.IsMissing(), nil 426 } 427 // Forward to not equal. 428 op = opIneq 429 default: 430 } 431 432 // Check if type conversion/inference is needed - it is needed 433 // if the Value is a byte-slice. 434 err = inferTypesForCmp(v, a) 435 if err != nil { 436 return false, err 437 } 438 439 // Check if either is nil 440 if v.IsNull() || a.IsNull() { 441 // If one is, both must be. 442 return boolCompare(op, v.IsNull(), a.IsNull()) 443 } 444 445 if a.IsMissing() || v.IsMissing() { 446 // If one is, both must be. 447 return boolCompare(op, v.IsMissing(), a.IsMissing()) 448 } 449 450 // Check array values 451 aArr, aOK := a.ToArray() 452 vArr, vOK := v.ToArray() 453 if aOK && vOK { 454 return arrayCompare(op, aArr, vArr) 455 } 456 457 isNumeric := v.isNumeric() && a.isNumeric() 458 if isNumeric { 459 intV, ok1i := v.ToInt() 460 intA, ok2i := a.ToInt() 461 if ok1i && ok2i { 462 return intCompare(op, intV, intA), nil 463 } 464 465 // If both values are numeric, then at least one is 466 // float since we got here, so we convert. 467 flV, _ := v.ToFloat() 468 flA, _ := a.ToFloat() 469 return floatCompare(op, flV, flA), nil 470 } 471 472 strV, ok1s := v.ToString() 473 strA, ok2s := a.ToString() 474 if ok1s && ok2s { 475 return stringCompare(op, strV, strA), nil 476 } 477 478 boolV, ok1b := v.ToBool() 479 boolA, ok2b := a.ToBool() 480 if ok1b && ok2b { 481 return boolCompare(op, boolV, boolA) 482 } 483 484 timestampV, ok1t := v.ToTimestamp() 485 timestampA, ok2t := a.ToTimestamp() 486 if ok1t && ok2t { 487 return timestampCompare(op, timestampV, timestampA), nil 488 } 489 490 // Types cannot be compared, they do not match. 491 switch op { 492 case opEq: 493 return false, nil 494 case opIneq: 495 return true, nil 496 } 497 return false, errCmpInvalidBoolOperator 498 } 499 500 func inferTypesForCmp(a *Value, b *Value) error { 501 _, okA := a.ToBytes() 502 _, okB := b.ToBytes() 503 switch { 504 case !okA && !okB: 505 // Both Values already have types 506 return nil 507 508 case okA && okB: 509 // Both Values are untyped so try the types in order: 510 // int, float, bool, string 511 512 // Check for numeric inference 513 iA, okAi := a.bytesToInt() 514 iB, okBi := b.bytesToInt() 515 if okAi && okBi { 516 a.setInt(iA) 517 b.setInt(iB) 518 return nil 519 } 520 521 fA, okAf := a.bytesToFloat() 522 fB, okBf := b.bytesToFloat() 523 if okAf && okBf { 524 a.setFloat(fA) 525 b.setFloat(fB) 526 return nil 527 } 528 529 // Check if they int and float combination. 530 if okAi && okBf { 531 a.setInt(iA) 532 b.setFloat(fA) 533 return nil 534 } 535 if okBi && okAf { 536 a.setFloat(fA) 537 b.setInt(iB) 538 return nil 539 } 540 541 // Not numeric types at this point. 542 543 // Check for bool inference 544 bA, okAb := a.bytesToBool() 545 bB, okBb := b.bytesToBool() 546 if okAb && okBb { 547 a.setBool(bA) 548 b.setBool(bB) 549 return nil 550 } 551 552 // Fallback to string 553 sA := a.bytesToString() 554 sB := b.bytesToString() 555 a.setString(sA) 556 b.setString(sB) 557 return nil 558 559 case okA && !okB: 560 // Here a has `a` is untyped, but `b` has a fixed 561 // type. 562 switch b.value.(type) { 563 case string: 564 s := a.bytesToString() 565 a.setString(s) 566 567 case int64, float64: 568 if iA, ok := a.bytesToInt(); ok { 569 a.setInt(iA) 570 } else if fA, ok := a.bytesToFloat(); ok { 571 a.setFloat(fA) 572 } else { 573 return fmt.Errorf("Could not convert %s to a number", a.String()) 574 } 575 576 case bool: 577 if bA, ok := a.bytesToBool(); ok { 578 a.setBool(bA) 579 } else { 580 return fmt.Errorf("Could not convert %s to a boolean", a.String()) 581 } 582 583 default: 584 return errCmpMismatchedTypes 585 } 586 return nil 587 588 case !okA && okB: 589 // swap arguments to avoid repeating code 590 return inferTypesForCmp(b, a) 591 592 default: 593 // Does not happen 594 return nil 595 } 596 } 597 598 // Value arithmetic functions: we do not expose them outside the 599 // module. All arithmetic works only on numeric values with automatic 600 // promotion to the "larger" type that can represent the value. TODO: 601 // Add support for large number arithmetic. 602 603 // Supported arithmetic operators 604 const ( 605 opPlus = "+" 606 opMinus = "-" 607 opDivide = "/" 608 opMultiply = "*" 609 opModulo = "%" 610 ) 611 612 // For arithmetic operations, if both values are numeric then the 613 // operation shall succeed. If the types are unknown automatic type 614 // conversion to a number is attempted. 615 func (v *Value) arithOp(op string, a *Value) error { 616 err := inferTypeForArithOp(v) 617 if err != nil { 618 return err 619 } 620 621 err = inferTypeForArithOp(a) 622 if err != nil { 623 return err 624 } 625 626 if !v.isNumeric() || !a.isNumeric() { 627 return errInvalidDataType(errArithMismatchedTypes) 628 } 629 630 if !isValidArithOperator(op) { 631 return errInvalidDataType(errArithMismatchedTypes) 632 } 633 634 intV, ok1i := v.ToInt() 635 intA, ok2i := a.ToInt() 636 switch { 637 case ok1i && ok2i: 638 res, err := intArithOp(op, intV, intA) 639 v.setInt(res) 640 return err 641 642 default: 643 // Convert arguments to float 644 flV, _ := v.ToFloat() 645 flA, _ := a.ToFloat() 646 res, err := floatArithOp(op, flV, flA) 647 v.setFloat(res) 648 return err 649 } 650 } 651 652 func inferTypeForArithOp(a *Value) error { 653 if _, ok := a.ToBytes(); !ok { 654 return nil 655 } 656 657 if i, ok := a.bytesToInt(); ok { 658 a.setInt(i) 659 return nil 660 } 661 662 if f, ok := a.bytesToFloat(); ok { 663 a.setFloat(f) 664 return nil 665 } 666 667 err := fmt.Errorf("Could not convert %q to a number", string(a.value.([]byte))) 668 return errInvalidDataType(err) 669 } 670 671 // All the bytesTo* functions defined below assume the value is a byte-slice. 672 673 // Converts untyped value into int. The bool return implies success - 674 // it returns false only if there is a conversion failure. 675 func (v Value) bytesToInt() (int64, bool) { 676 bytes, _ := v.ToBytes() 677 i, err := strconv.ParseInt(strings.TrimSpace(string(bytes)), 10, 64) 678 return i, err == nil 679 } 680 681 // Converts untyped value into float. The bool return implies success 682 // - it returns false only if there is a conversion failure. 683 func (v Value) bytesToFloat() (float64, bool) { 684 bytes, _ := v.ToBytes() 685 i, err := strconv.ParseFloat(strings.TrimSpace(string(bytes)), 64) 686 return i, err == nil 687 } 688 689 // Converts untyped value into bool. The second bool return implies 690 // success - it returns false in case of a conversion failure. 691 func (v Value) bytesToBool() (val bool, ok bool) { 692 bytes, _ := v.ToBytes() 693 ok = true 694 switch strings.ToLower(strings.TrimSpace(string(bytes))) { 695 case "t", "true", "1": 696 val = true 697 case "f", "false", "0": 698 val = false 699 default: 700 ok = false 701 } 702 return val, ok 703 } 704 705 // bytesToString - never fails, but returns empty string if value is not bytes. 706 func (v Value) bytesToString() string { 707 bytes, _ := v.ToBytes() 708 return string(bytes) 709 } 710 711 // Calculates minimum or maximum of v and a and assigns the result to 712 // v - it works only on numeric arguments, where `v` is already 713 // assumed to be numeric. Attempts conversion to numeric type for `a` 714 // (first int, then float) only if the underlying values do not have a 715 // type. 716 func (v *Value) minmax(a *Value, isMax, isFirstRow bool) error { 717 err := inferTypeForArithOp(a) 718 if err != nil { 719 return err 720 } 721 722 if !a.isNumeric() { 723 return errArithMismatchedTypes 724 } 725 726 // In case of first row, set v to a. 727 if isFirstRow { 728 intA, okI := a.ToInt() 729 if okI { 730 v.setInt(intA) 731 return nil 732 } 733 floatA, _ := a.ToFloat() 734 v.setFloat(floatA) 735 return nil 736 } 737 738 intV, ok1i := v.ToInt() 739 intA, ok2i := a.ToInt() 740 if ok1i && ok2i { 741 result := intV 742 if !isMax { 743 if intA < result { 744 result = intA 745 } 746 } else { 747 if intA > result { 748 result = intA 749 } 750 } 751 v.setInt(result) 752 return nil 753 } 754 755 floatV, _ := v.ToFloat() 756 floatA, _ := a.ToFloat() 757 var result float64 758 if !isMax { 759 result = math.Min(floatV, floatA) 760 } else { 761 result = math.Max(floatV, floatA) 762 } 763 v.setFloat(result) 764 return nil 765 } 766 767 func inferTypeAsTimestamp(v *Value) error { 768 if s, ok := v.ToString(); ok { 769 t, err := parseSQLTimestamp(s) 770 if err != nil { 771 return err 772 } 773 v.setTimestamp(t) 774 } else if b, ok := v.ToBytes(); ok { 775 s := string(b) 776 t, err := parseSQLTimestamp(s) 777 if err != nil { 778 return err 779 } 780 v.setTimestamp(t) 781 } 782 return nil 783 } 784 785 // inferTypeAsString is used to convert untyped values to string - it 786 // is called when the caller requires a string context to proceed. 787 func inferTypeAsString(v *Value) { 788 b, ok := v.ToBytes() 789 if !ok { 790 return 791 } 792 793 v.setString(string(b)) 794 } 795 796 func isValidComparisonOperator(op string) bool { 797 switch op { 798 case opLt, opLte, opGt, opGte, opEq, opIneq, opIs, opIsNot: 799 default: 800 return false 801 } 802 return true 803 } 804 805 func intCompare(op string, left, right int64) bool { 806 switch op { 807 case opLt: 808 return left < right 809 case opLte: 810 return left <= right 811 case opGt: 812 return left > right 813 case opGte: 814 return left >= right 815 case opEq: 816 return left == right 817 case opIneq: 818 return left != right 819 } 820 // This case does not happen 821 return false 822 } 823 824 func floatCompare(op string, left, right float64) bool { 825 diff := math.Abs(left - right) 826 switch op { 827 case opLt: 828 return left < right 829 case opLte: 830 return left <= right 831 case opGt: 832 return left > right 833 case opGte: 834 return left >= right 835 case opEq: 836 return diff < floatCmpTolerance 837 case opIneq: 838 return diff > floatCmpTolerance 839 } 840 // This case does not happen 841 return false 842 } 843 844 func stringCompare(op string, left, right string) bool { 845 switch op { 846 case opLt: 847 return left < right 848 case opLte: 849 return left <= right 850 case opGt: 851 return left > right 852 case opGte: 853 return left >= right 854 case opEq: 855 return left == right 856 case opIneq: 857 return left != right 858 } 859 // This case does not happen 860 return false 861 } 862 863 func boolCompare(op string, left, right bool) (bool, error) { 864 switch op { 865 case opEq: 866 return left == right, nil 867 case opIneq: 868 return left != right, nil 869 default: 870 return false, errCmpInvalidBoolOperator 871 } 872 } 873 874 func arrayCompare(op string, left, right []Value) (bool, error) { 875 switch op { 876 case opEq: 877 if len(left) != len(right) { 878 return false, nil 879 } 880 for i, l := range left { 881 eq, err := l.compareOp(op, &right[i]) 882 if !eq || err != nil { 883 return eq, err 884 } 885 } 886 return true, nil 887 case opIneq: 888 for i, l := range left { 889 eq, err := l.compareOp(op, &right[i]) 890 if eq || err != nil { 891 return eq, err 892 } 893 } 894 return false, nil 895 default: 896 return false, errCmpInvalidBoolOperator 897 } 898 } 899 900 func isValidArithOperator(op string) bool { 901 switch op { 902 case opPlus: 903 case opMinus: 904 case opDivide: 905 case opMultiply: 906 case opModulo: 907 default: 908 return false 909 } 910 return true 911 } 912 913 // Overflow errors are ignored. 914 func intArithOp(op string, left, right int64) (int64, error) { 915 switch op { 916 case opPlus: 917 return left + right, nil 918 case opMinus: 919 return left - right, nil 920 case opDivide: 921 if right == 0 { 922 return 0, errArithDivideByZero 923 } 924 return left / right, nil 925 case opMultiply: 926 return left * right, nil 927 case opModulo: 928 if right == 0 { 929 return 0, errArithDivideByZero 930 } 931 return left % right, nil 932 } 933 // This does not happen 934 return 0, nil 935 } 936 937 // Overflow errors are ignored. 938 func floatArithOp(op string, left, right float64) (float64, error) { 939 switch op { 940 case opPlus: 941 return left + right, nil 942 case opMinus: 943 return left - right, nil 944 case opDivide: 945 if right == 0 { 946 return 0, errArithDivideByZero 947 } 948 return left / right, nil 949 case opMultiply: 950 return left * right, nil 951 case opModulo: 952 if right == 0 { 953 return 0, errArithDivideByZero 954 } 955 return math.Mod(left, right), nil 956 } 957 // This does not happen 958 return 0, nil 959 }