vitess.io/vitess@v0.16.2/go/vt/vtgate/evalengine/bit.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package evalengine
    18  
    19  import (
    20  	"vitess.io/vitess/go/sqltypes"
    21  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    22  	"vitess.io/vitess/go/vt/vterrors"
    23  )
    24  
    25  type (
    26  	BitwiseExpr struct {
    27  		BinaryExpr
    28  		Op BitwiseOp
    29  	}
    30  
    31  	BitwiseNotExpr struct {
    32  		UnaryExpr
    33  	}
    34  
    35  	BitwiseOp interface {
    36  		BitwiseOp() string
    37  	}
    38  
    39  	BitwiseBinaryOp interface {
    40  		BitwiseOp
    41  		numeric(left, right uint64) uint64
    42  		binary(left, right []byte) []byte
    43  	}
    44  
    45  	BitwiseShiftOp interface {
    46  		BitwiseOp
    47  		numeric(num, shift uint64) uint64
    48  		binary(num []byte, shift uint64) []byte
    49  	}
    50  
    51  	OpBitAnd        struct{}
    52  	OpBitOr         struct{}
    53  	OpBitXor        struct{}
    54  	OpBitShiftLeft  struct{}
    55  	OpBitShiftRight struct{}
    56  )
    57  
    58  func (b *BitwiseNotExpr) eval(env *ExpressionEnv, result *EvalResult) {
    59  	var inner EvalResult
    60  	inner.init(env, b.Inner)
    61  
    62  	if inner.isNull() {
    63  		result.setNull()
    64  		return
    65  	}
    66  
    67  	if inner.isBitwiseBinaryString() {
    68  		in := inner.bytes()
    69  		out := make([]byte, len(in))
    70  
    71  		for i := range in {
    72  			out[i] = ^in[i]
    73  		}
    74  
    75  		result.setRaw(sqltypes.VarBinary, out, collationBinary)
    76  	} else {
    77  		inner.makeUnsignedIntegral()
    78  		result.setUint64(^inner.uint64())
    79  	}
    80  }
    81  
    82  func (b *BitwiseNotExpr) typeof(env *ExpressionEnv) (sqltypes.Type, flag) {
    83  	tt, f := b.Inner.typeof(env)
    84  	if tt == sqltypes.VarBinary && f&(flagHex|flagBit) == 0 {
    85  		return sqltypes.VarBinary, f
    86  	}
    87  	return sqltypes.Uint64, f
    88  }
    89  
    90  func (o OpBitShiftRight) BitwiseOp() string                { return ">>" }
    91  func (o OpBitShiftRight) numeric(num, shift uint64) uint64 { return num >> shift }
    92  
    93  func (o OpBitShiftRight) binary(num []byte, shift uint64) []byte {
    94  	var (
    95  		bits   = int(shift % 8)
    96  		bytes  = int(shift / 8)
    97  		length = len(num)
    98  		out    = make([]byte, length)
    99  	)
   100  
   101  	for i := length - 1; i >= 0; i-- {
   102  		switch {
   103  		case i > bytes:
   104  			out[i] = num[i-bytes-1] << (8 - bits)
   105  			fallthrough
   106  		case i == bytes:
   107  			out[i] |= num[i-bytes] >> bits
   108  		}
   109  	}
   110  	return out
   111  }
   112  
   113  func (o OpBitShiftLeft) BitwiseOp() string                { return "<<" }
   114  func (o OpBitShiftLeft) numeric(num, shift uint64) uint64 { return num << shift }
   115  
   116  func (o OpBitShiftLeft) binary(num []byte, shift uint64) []byte {
   117  	var (
   118  		bits   = int(shift % 8)
   119  		bytes  = int(shift / 8)
   120  		length = len(num)
   121  		out    = make([]byte, length)
   122  	)
   123  
   124  	for i := 0; i < length; i++ {
   125  		pos := i + bytes + 1
   126  		switch {
   127  		case pos < length:
   128  			out[i] = num[pos] >> (8 - bits)
   129  			fallthrough
   130  		case pos == length:
   131  			out[i] |= num[pos-1] << bits
   132  		}
   133  	}
   134  	return out
   135  }
   136  
   137  func (o OpBitXor) numeric(left, right uint64) uint64 { return left ^ right }
   138  
   139  func (o OpBitXor) binary(left, right []byte) (out []byte) {
   140  	out = make([]byte, len(left))
   141  	for i := range out {
   142  		out[i] = left[i] ^ right[i]
   143  	}
   144  	return
   145  }
   146  
   147  func (o OpBitXor) BitwiseOp() string { return "^" }
   148  
   149  func (o OpBitOr) numeric(left, right uint64) uint64 { return left | right }
   150  
   151  func (o OpBitOr) binary(left, right []byte) (out []byte) {
   152  	out = make([]byte, len(left))
   153  	for i := range out {
   154  		out[i] = left[i] | right[i]
   155  	}
   156  	return
   157  }
   158  
   159  func (o OpBitOr) BitwiseOp() string { return "|" }
   160  
   161  func (o OpBitAnd) numeric(left, right uint64) uint64 { return left & right }
   162  
   163  func (o OpBitAnd) binary(left, right []byte) (out []byte) {
   164  	out = make([]byte, len(left))
   165  	for i := range out {
   166  		out[i] = left[i] & right[i]
   167  	}
   168  	return
   169  }
   170  
   171  func (o OpBitAnd) BitwiseOp() string { return "&" }
   172  
   173  func (bit *BitwiseExpr) eval(env *ExpressionEnv, result *EvalResult) {
   174  	var l, r EvalResult
   175  
   176  	l.init(env, bit.Left)
   177  	r.init(env, bit.Right)
   178  
   179  	if l.isNull() || r.isNull() {
   180  		result.setNull()
   181  		return
   182  	}
   183  
   184  	switch op := bit.Op.(type) {
   185  	case BitwiseBinaryOp:
   186  		/*
   187  			The result type depends on whether the arguments are evaluated as binary strings or numbers:
   188  			Binary-string evaluation occurs when the arguments have a binary string type, and at least one of them is
   189  			not a hexadecimal literal, bit literal, or NULL literal. Numeric evaluation occurs otherwise, with argument
   190  			conversion to unsigned 64-bit integers as necessary. Binary-string evaluation produces a binary string of
   191  			the same length as the arguments. If the arguments have unequal lengths, an ER_INVALID_BITWISE_OPERANDS_SIZE
   192  			error occurs. Numeric evaluation produces an unsigned 64-bit integer.
   193  		*/
   194  		if l.typeof() == sqltypes.VarBinary && r.typeof() == sqltypes.VarBinary && (!l.hasFlag(flagHex|flagBit) || !r.hasFlag(flagHex|flagBit)) {
   195  			b1 := l.bytes()
   196  			b2 := r.bytes()
   197  
   198  			if len(b1) != len(b2) {
   199  				throwEvalError(vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Binary operands of bitwise operators must be of equal length"))
   200  			}
   201  			result.setRaw(sqltypes.VarBinary, op.binary(b1, b2), collationBinary)
   202  		} else {
   203  			l.makeUnsignedIntegral()
   204  			r.makeUnsignedIntegral()
   205  			result.setUint64(op.numeric(l.uint64(), r.uint64()))
   206  		}
   207  
   208  	case BitwiseShiftOp:
   209  		/*
   210  			The result type depends on whether the bit argument is evaluated as a binary string or number:
   211  			Binary-string evaluation occurs when the bit argument has a binary string type, and is not a hexadecimal
   212  			literal, bit literal, or NULL literal. Numeric evaluation occurs otherwise, with argument conversion to an
   213  			unsigned 64-bit integer as necessary.
   214  		*/
   215  		if l.isBitwiseBinaryString() {
   216  			r.makeUnsignedIntegral()
   217  			result.setRaw(sqltypes.VarBinary, op.binary(l.bytes(), r.uint64()), collationBinary)
   218  		} else {
   219  			l.makeUnsignedIntegral()
   220  			r.makeUnsignedIntegral()
   221  			result.setUint64(op.numeric(l.uint64(), r.uint64()))
   222  		}
   223  	}
   224  }
   225  
   226  func (bit *BitwiseExpr) typeof(env *ExpressionEnv) (sqltypes.Type, flag) {
   227  	t1, f1 := bit.Left.typeof(env)
   228  	t2, f2 := bit.Right.typeof(env)
   229  
   230  	switch bit.Op.(type) {
   231  	case BitwiseBinaryOp:
   232  		if t1 == sqltypes.VarBinary && t2 == sqltypes.VarBinary &&
   233  			(f1&(flagHex|flagBit) == 0 || f2&(flagHex|flagBit) == 0) {
   234  			return sqltypes.VarBinary, f1 | f2
   235  		}
   236  	case BitwiseShiftOp:
   237  		if t1 == sqltypes.VarBinary && (f1&(flagHex|flagBit)) == 0 {
   238  			return sqltypes.VarBinary, f1 | f2
   239  		}
   240  	}
   241  
   242  	return sqltypes.Uint64, f1 | f2
   243  }
   244  
   245  var _ BitwiseBinaryOp = (*OpBitAnd)(nil)
   246  var _ BitwiseBinaryOp = (*OpBitOr)(nil)
   247  var _ BitwiseBinaryOp = (*OpBitXor)(nil)
   248  var _ BitwiseShiftOp = (*OpBitShiftLeft)(nil)
   249  var _ BitwiseShiftOp = (*OpBitShiftRight)(nil)