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)