github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/expreval/compare_ops.go (about) 1 // Copyright 2020 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package expreval 16 17 import ( 18 "context" 19 20 "github.com/dolthub/go-mysql-server/sql/expression" 21 22 "github.com/dolthub/dolt/go/store/types" 23 ) 24 25 func compareLiterals(l1, l2 *expression.Literal) (int, error) { 26 return l1.Type().Compare(l1.Value(), l2.Value()) 27 } 28 29 // CompareOp is an interface for comparing values 30 type CompareOp interface { 31 // CompareLiterals compares two go-mysql-server literals 32 CompareLiterals(l1, l2 *expression.Literal) (bool, error) 33 // CompareNomsValues compares two noms values 34 CompareNomsValues(ctx context.Context, v1, v2 types.Value) (bool, error) 35 // CompareToNil compares a noms value to nil using sql logic rules 36 CompareToNil(v2 types.Value) (bool, error) 37 } 38 39 // EqualsOp implements the CompareOp interface implementing equality logic 40 type EqualsOp struct{} 41 42 // CompareLiterals compares two go-mysql-server literals for equality 43 func (op EqualsOp) CompareLiterals(l1, l2 *expression.Literal) (bool, error) { 44 n, err := compareLiterals(l1, l2) 45 46 if err != nil { 47 return false, err 48 } 49 50 return n == 0, nil 51 } 52 53 // CompareNomsValues compares two noms values for equality 54 func (op EqualsOp) CompareNomsValues(_ context.Context, v1, v2 types.Value) (bool, error) { 55 return v1.Equals(v2), nil 56 } 57 58 // CompareToNil always returns false as values are neither greater than, less than, or equal to nil 59 // except for equality op, the compared value is null. 60 func (op EqualsOp) CompareToNil(v types.Value) (bool, error) { 61 if v == types.NullValue { 62 return true, nil 63 } 64 return false, nil 65 } 66 67 // GreaterOp implements the CompareOp interface implementing greater than logic 68 type GreaterOp struct { 69 vr types.ValueReader 70 } 71 72 // CompareLiterals compares two go-mysql-server literals returning true if the value of the first 73 // is greater than the second. 74 func (op GreaterOp) CompareLiterals(l1, l2 *expression.Literal) (bool, error) { 75 n, err := compareLiterals(l1, l2) 76 77 if err != nil { 78 return false, err 79 } 80 81 return n > 0, nil 82 } 83 84 // CompareNomsValues compares two noms values returning true if the of the first 85 // is greater than the second. 86 func (op GreaterOp) CompareNomsValues(ctx context.Context, v1, v2 types.Value) (bool, error) { 87 eq := v1.Equals(v2) 88 89 if eq { 90 return false, nil 91 } 92 93 lt, err := v1.Less(ctx, op.vr.Format(), v2) 94 95 if err != nil { 96 return false, nil 97 } 98 99 return !lt, err 100 } 101 102 // CompareToNil always returns false as values are neither greater than, less than, or equal to nil 103 func (op GreaterOp) CompareToNil(types.Value) (bool, error) { 104 return false, nil 105 } 106 107 // GreaterEqualOp implements the CompareOp interface implementing greater than or equal to logic 108 type GreaterEqualOp struct { 109 vr types.ValueReader 110 } 111 112 // CompareLiterals compares two go-mysql-server literals returning true if the value of the first 113 // is greater than or equal to the second. 114 func (op GreaterEqualOp) CompareLiterals(l1, l2 *expression.Literal) (bool, error) { 115 n, err := compareLiterals(l1, l2) 116 117 if err != nil { 118 return false, err 119 } 120 121 return n >= 0, nil 122 } 123 124 // CompareNomsValues compares two noms values returning true if the of the first 125 // is greater or equal to than the second. 126 func (op GreaterEqualOp) CompareNomsValues(ctx context.Context, v1, v2 types.Value) (bool, error) { 127 res, err := v1.Less(ctx, op.vr.Format(), v2) 128 129 if err != nil { 130 return false, err 131 } 132 133 return !res, nil 134 } 135 136 // CompareToNil always returns false as values are neither greater than, less than, or equal to nil 137 func (op GreaterEqualOp) CompareToNil(types.Value) (bool, error) { 138 return false, nil 139 } 140 141 // LessOp implements the CompareOp interface implementing less than logic 142 type LessOp struct { 143 vr types.ValueReader 144 } 145 146 // CompareLiterals compares two go-mysql-server literals returning true if the value of the first 147 // is less than the second. 148 func (op LessOp) CompareLiterals(l1, l2 *expression.Literal) (bool, error) { 149 n, err := compareLiterals(l1, l2) 150 151 if err != nil { 152 return false, err 153 } 154 155 return n < 0, nil 156 } 157 158 // CompareNomsValues compares two noms values returning true if the of the first 159 // is less than the second. 160 func (op LessOp) CompareNomsValues(ctx context.Context, v1, v2 types.Value) (bool, error) { 161 return v1.Less(ctx, op.vr.Format(), v2) 162 } 163 164 // CompareToNil always returns false as values are neither greater than, less than, or equal to nil 165 func (op LessOp) CompareToNil(types.Value) (bool, error) { 166 return false, nil 167 } 168 169 // LessEqualOp implements the CompareOp interface implementing less than or equal to logic 170 type LessEqualOp struct { 171 vr types.ValueReader 172 } 173 174 // CompareLiterals compares two go-mysql-server literals returning true if the value of the first 175 // is less than or equal to the second. 176 func (op LessEqualOp) CompareLiterals(l1, l2 *expression.Literal) (bool, error) { 177 n, err := compareLiterals(l1, l2) 178 179 if err != nil { 180 return false, err 181 } 182 183 return n <= 0, nil 184 } 185 186 // CompareNomsValues compares two noms values returning true if the of the first 187 // is less than or equal to the second. 188 func (op LessEqualOp) CompareNomsValues(ctx context.Context, v1, v2 types.Value) (bool, error) { 189 eq := v1.Equals(v2) 190 191 if eq { 192 return true, nil 193 } 194 195 return v1.Less(ctx, op.vr.Format(), v2) 196 } 197 198 // CompareToNil always returns false as values are neither greater than, less than, or equal to nil 199 func (op LessEqualOp) CompareToNil(types.Value) (bool, error) { 200 return false, nil 201 }