[Tarantool-patches] [PATCH v5 21/52] sql: introduce bitwise operations for MEM

imeevma at tarantool.org imeevma at tarantool.org
Fri Apr 9 21:11:40 MSK 2021


Thank you for the review! My answers and new patch below.


On 30.03.2021 02:03, Vladislav Shpilevoy wrote:
> Thanks for the patch!
>
> On 23.03.2021 10:35, Mergen Imeev via Tarantool-patches wrote:
>> This patch introduces mem_bitwise(). Function mem_bitwise() executes
>> bitwise operations with two operands and writes the result to the third
>> MEM.
>>
>> Part of #5818
>> ---
>>  src/box/sql/mem.c  | 51 +++++++++++++++++++++++++++++++++++++++++++
>>  src/box/sql/mem.h  |  3 +++
>>  src/box/sql/vdbe.c | 54 +++-------------------------------------------
>>  3 files changed, 57 insertions(+), 51 deletions(-)
>>
>> diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
>> index 8119644ed..2b455e39f 100644
>> --- a/src/box/sql/mem.c
>> +++ b/src/box/sql/mem.c
>> @@ -556,6 +556,57 @@ mem_arithmetic(const struct Mem *left, const struct Mem *right,
>>    return 0;
>>  }
>>  
>> +int
>> +mem_bitwise(struct Mem *left, struct Mem *right, struct Mem *result, int op)
>
> Would be better to split it into separate functions. Also why is OP_BitNot
> separated? How is it much different from, say, OP_BitAnd?
>
Done. I splitted this function. Also, I moved function mem_bit_not() to this
patch.

> Besides, having OP_BitNot in mem.c would allow to make sqlVdbeIntValue static
> inside mem.c.
I didn't make this function static since I will remove it in a few patches.


New patch:

commit cc2e656974210a7f4f8e3c5402adf1bd90c5576f
Author: Mergen Imeev <imeevma at gmail.com>
Date:   Sun Mar 14 22:20:11 2021 +0300

    sql: introduce bitwise operations for MEM
    
    This patch introduces mem_bit_and(), mem_bit_or(), mem_shift_left(),
    mem_shift_right(), and mem_bit_not(), which perform bitwise operations
    on MEM.
    
    Part of #5818

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index eee72a7fe..aeb801c7c 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -624,6 +624,115 @@ mem_rem(const struct Mem *left, const struct Mem *right, struct Mem *result)
  return 0;
 }
 
+static int
+bitwise_prepare(const struct Mem *left, const struct Mem *right,
+   int64_t *a, int64_t *b)
+{
+ bool unused;
+ if (sqlVdbeIntValue(left, a, &unused) != 0) {
+   diag_set(ClientError, ER_SQL_TYPE_MISMATCH, mem_str(left),
+      "integer");
+   return -1;
+ }
+ if (sqlVdbeIntValue(right, b, &unused) != 0) {
+   diag_set(ClientError, ER_SQL_TYPE_MISMATCH, mem_str(right),
+      "integer");
+   return -1;
+ }
+ return 0;
+}
+
+int
+mem_bit_and(const struct Mem *left, const struct Mem *right, struct Mem *result)
+{
+ if (is_result_null(left, right, result, FIELD_TYPE_INTEGER))
+   return 0;
+ int64_t a;
+ int64_t b;
+ if (bitwise_prepare(left, right, &a, &b) != 0)
+   return -1;
+ result->u.i = a & b;
+ result->flags = result->u.i < 0 ? MEM_Int : MEM_UInt;
+ return 0;
+}
+
+int
+mem_bit_or(const struct Mem *left, const struct Mem *right, struct Mem *result)
+{
+ if (is_result_null(left, right, result, FIELD_TYPE_INTEGER))
+   return 0;
+ int64_t a;
+ int64_t b;
+ if (bitwise_prepare(left, right, &a, &b) != 0)
+   return -1;
+ result->u.i = a | b;
+ result->flags = result->u.i < 0 ? MEM_Int : MEM_UInt;
+ return 0;
+}
+
+int
+mem_shift_left(const struct Mem *left, const struct Mem *right,
+        struct Mem *result)
+{
+ if (is_result_null(left, right, result, FIELD_TYPE_INTEGER))
+   return 0;
+ int64_t a;
+ int64_t b;
+ if (bitwise_prepare(left, right, &a, &b) != 0)
+   return -1;
+ if (b <= -64)
+   result->u.i = a >= 0 ? 0 : -1;
+ else if (b < 0)
+   result->u.i = a >> -b;
+ else if (b > 64)
+   result->u.i = 0;
+ else
+   result->u.i = a << b;
+ result->flags = result->u.i < 0 ? MEM_Int : MEM_UInt;
+ return 0;
+}
+
+int
+mem_shift_right(const struct Mem *left, const struct Mem *right,
+   struct Mem *result)
+{
+ if (is_result_null(left, right, result, FIELD_TYPE_INTEGER))
+   return 0;
+ int64_t a;
+ int64_t b;
+ if (bitwise_prepare(left, right, &a, &b) != 0)
+   return -1;
+ if (b <= -64)
+   result->u.i = 0;
+ else if (b < 0)
+   result->u.i = a << -b;
+ else if (b > 64)
+   result->u.i = a >= 0 ? 0 : -1;
+ else
+   result->u.i = a >> b;
+ result->flags = result->u.i < 0 ? MEM_Int : MEM_UInt;
+ return 0;
+}
+
+int
+mem_bit_not(const struct Mem *mem, struct Mem *result)
+{
+ mem_clear(result);
+ result->field_type = FIELD_TYPE_INTEGER;
+ if ((mem->flags & MEM_Null) != 0)
+   return 0;
+ int64_t i;
+ bool unused;
+ if (sqlVdbeIntValue(mem, &i, &unused) != 0) {
+   diag_set(ClientError, ER_SQL_TYPE_MISMATCH, mem_str(mem),
+      "integer");
+   return -1;
+ }
+ result->u.i = ~i;
+ result->flags = result->u.i < 0 ? MEM_Int : MEM_UInt;
+ return 0;
+}
+
 static int
 compare_blobs(const struct Mem *a, const struct Mem *b, int *result)
 {
@@ -2065,7 +2174,7 @@ mem_value_bool(const struct Mem *mem, bool *b)
  * If pMem represents a string value, its encoding might be changed.
  */
 int
-sqlVdbeIntValue(Mem * pMem, int64_t *i, bool *is_neg)
+sqlVdbeIntValue(const struct Mem *pMem, int64_t *i, bool *is_neg)
 {
  int flags;
  assert(EIGHT_BYTE_ALIGNMENT(pMem));
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index 6c022d8d8..e3b55644e 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -226,6 +226,35 @@ mem_div(const struct Mem *left, const struct Mem *right, struct Mem *result);
 int
 mem_rem(const struct Mem *left, const struct Mem *right, struct Mem *result);
 
+/** Perform a bitwise AND for two MEMs and write the result to the third MEM. */
+int
+mem_bit_and(const struct Mem *left, const struct Mem *right,
+     struct Mem *result);
+
+/** Perform a bitwise OR for two MEMs and write the result to the third MEM. */
+int
+mem_bit_or(const struct Mem *left, const struct Mem *right, struct Mem *result);
+
+/**
+ * Perform a bitwise left shift for the first MEM by value from the second MEM
+ * and write the result to the third MEM.
+ */
+int
+mem_shift_left(const struct Mem *left, const struct Mem *right,
+        struct Mem *result);
+
+/**
+ * Perform a bitwise right shift for the first MEM by value from the second MEM
+ * and write the result to the third MEM.
+ */
+int
+mem_shift_right(const struct Mem *left, const struct Mem *right,
+   struct Mem *result);
+
+/** Perform a bitwise NOT to the MEM and write the result to the second MEM. */
+int
+mem_bit_not(const struct Mem *mem, struct Mem *result);
+
 /** Compare two non-NULL MEMs and return the result of comparison. */
 int
 mem_compare(const struct Mem *left, const struct Mem *right, int *result,
@@ -464,7 +493,7 @@ releaseMemArray(Mem * p, int N);
 
 int
 mem_value_bool(const struct Mem *mem, bool *b);
-int sqlVdbeIntValue(struct Mem *, int64_t *, bool *is_neg);
+int sqlVdbeIntValue(const struct Mem *, int64_t *, bool *is_neg);
 int sqlVdbeRealValue(struct Mem *, double *);
 const void *
 sql_value_blob(struct Mem *);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 6a923a8b6..2ad681fa4 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1341,6 +1341,16 @@ case OP_FunctionByName: {
  * store the result in register P3.
  * If either input is NULL, the result is NULL.
  */
+case OP_BitAnd: {               /* same as TK_BITAND, in1, in2, out3 */
+ pIn1 = &aMem[pOp->p1];
+ pIn2 = &aMem[pOp->p2];
+ pOut = &aMem[pOp->p3];
+ if (mem_bit_and(pIn2, pIn1, pOut) != 0)
+   goto abort_due_to_error;
+ assert(pOut->field_type == FIELD_TYPE_INTEGER);
+ break;
+}
+
 /* Opcode: BitOr P1 P2 P3 * *
  * Synopsis: r[P3]=r[P1]|r[P2]
  *
@@ -1348,6 +1358,16 @@ case OP_FunctionByName: {
  * store the result in register P3.
  * If either input is NULL, the result is NULL.
  */
+case OP_BitOr: {                /* same as TK_BITOR, in1, in2, out3 */
+ pIn1 = &aMem[pOp->p1];
+ pIn2 = &aMem[pOp->p2];
+ pOut = &aMem[pOp->p3];
+ if (mem_bit_or(pIn2, pIn1, pOut) != 0)
+   goto abort_due_to_error;
+ assert(pOut->field_type == FIELD_TYPE_INTEGER);
+ break;
+}
+
 /* Opcode: ShiftLeft P1 P2 P3 * *
  * Synopsis: r[P3]=r[P2]<<r[P1]
  *
@@ -1356,6 +1376,16 @@ case OP_FunctionByName: {
  * Store the result in register P3.
  * If either input is NULL, the result is NULL.
  */
+case OP_ShiftLeft: {            /* same as TK_LSHIFT, in1, in2, out3 */
+ pIn1 = &aMem[pOp->p1];
+ pIn2 = &aMem[pOp->p2];
+ pOut = &aMem[pOp->p3];
+ if (mem_shift_left(pIn2, pIn1, pOut) != 0)
+   goto abort_due_to_error;
+ assert(pOut->field_type == FIELD_TYPE_INTEGER);
+ break;
+}
+
 /* Opcode: ShiftRight P1 P2 P3 * *
  * Synopsis: r[P3]=r[P2]>>r[P1]
  *
@@ -1364,64 +1394,13 @@ case OP_FunctionByName: {
  * Store the result in register P3.
  * If either input is NULL, the result is NULL.
  */
-case OP_BitAnd:                 /* same as TK_BITAND, in1, in2, out3 */
-case OP_BitOr:                  /* same as TK_BITOR, in1, in2, out3 */
-case OP_ShiftLeft:              /* same as TK_LSHIFT, in1, in2, out3 */
 case OP_ShiftRight: {           /* same as TK_RSHIFT, in1, in2, out3 */
- i64 iA;
- u64 uA;
- i64 iB;
- u8 op;
-
  pIn1 = &aMem[pOp->p1];
  pIn2 = &aMem[pOp->p2];
- pOut = vdbe_prepare_null_out(p, pOp->p3);
- if (mem_is_any_null(pIn1, pIn2)) {
-   /* Force NULL be of type INTEGER. */
-   pOut->field_type = FIELD_TYPE_INTEGER;
-   break;
- }
- bool unused;
- if (sqlVdbeIntValue(pIn2, (int64_t *) &iA, &unused) != 0) {
-   diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-      mem_str(pIn2), "integer");
-   goto abort_due_to_error;
- }
- if (sqlVdbeIntValue(pIn1, (int64_t *) &iB, &unused) != 0) {
-   diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-      mem_str(pIn1), "integer");
+ pOut = &aMem[pOp->p3];
+ if (mem_shift_right(pIn2, pIn1, pOut) != 0)
    goto abort_due_to_error;
- }
- op = pOp->opcode;
- if (op==OP_BitAnd) {
-   iA &= iB;
- } else if (op==OP_BitOr) {
-   iA |= iB;
- } else if (iB!=0) {
-   assert(op==OP_ShiftRight || op==OP_ShiftLeft);
-
-   /* If shifting by a negative amount, shift in the other direction */
-   if (iB<0) {
-     assert(OP_ShiftRight==OP_ShiftLeft+1);
-     op = 2*OP_ShiftLeft + 1 - op;
-     iB = iB>(-64) ? -iB : 64;
-   }
-
-   if (iB>=64) {
-     iA = (iA>=0 || op==OP_ShiftLeft) ? 0 : -1;
-   } else {
-     memcpy(&uA, &iA, sizeof(uA));
-     if (op==OP_ShiftLeft) {
-       uA <<= iB;
-     } else {
-       uA >>= iB;
-       /* Sign-extend on a right shift of a negative number */
-       if (iA<0) uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-iB);
-     }
-     memcpy(&iA, &uA, sizeof(iA));
-   }
- }
- mem_set_i64(pOut, iA);
+ assert(pOut->field_type == FIELD_TYPE_INTEGER);
  break;
 }
 
@@ -1903,19 +1882,9 @@ case OP_Not: {                /* same as TK_NOT, in1, out2 */
  */
 case OP_BitNot: {             /* same as TK_BITNOT, in1, out2 */
  pIn1 = &aMem[pOp->p1];
- pOut = vdbe_prepare_null_out(p, pOp->p2);
- /* Force NULL be of type INTEGER. */
- pOut->field_type = FIELD_TYPE_INTEGER;
- if (!mem_is_null(pIn1)) {
-   int64_t i;
-   bool is_neg;
-   if (sqlVdbeIntValue(pIn1, &i, &is_neg) != 0) {
-     diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-        mem_str(pIn1), "integer");
-     goto abort_due_to_error;
-   }
-   mem_set_i64(pOut, ~i);
- }
+ pOut = &aMem[pOp->p2];
+ if (mem_bit_not(pIn1, pOut) != 0)
+   goto abort_due_to_error;
  break;
 }
 


More information about the Tarantool-patches mailing list