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  }