From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 3AFDB6EC5D; Fri, 9 Apr 2021 21:11:43 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 3AFDB6EC5D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1617991903; bh=u5gdgn7Aj5l4f178JXcJp7JNDzjIyq5n7BYVUUife9g=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=DigjKBAXYO4WKLnv8Te2kX857oj9UKtR/VNdHJhUm/XA6LBJGRJbJ+5S4mirb3RK+ SexER1594nySRfpDdZUtKYSWcgPSydNEEWrP41OApAapHw2jUQHZcrDCJyHhHxvYNA qiOTZ61dt9p4PbRq28VsJH8MIAi2+ctiNDY4I2Ks= Received: from smtpng1.m.smailru.net (smtpng1.m.smailru.net [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 1DFB56EC5D for ; Fri, 9 Apr 2021 21:11:42 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 1DFB56EC5D Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1lUvbZ-0004HS-0t; Fri, 09 Apr 2021 21:11:41 +0300 To: v.shpilevoy@tarantool.org, tsafin@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Fri, 9 Apr 2021 21:11:40 +0300 Message-Id: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-7564579A: 78E4E2B564C1792B X-77F55803: 4F1203BC0FB41BD92FFCB8E6708E7480EBD5CA77A668ECB87DA2124B0A8E6609182A05F53808504032D67F1BD1B4F723A0E38C5218D6DCA3957229D26FEF661059F2FEF095E4F5D9 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE796563325B6E011C8C2099A533E45F2D0395957E7521B51C2CFCAF695D4D8E9FCEA1F7E6F0F101C6778DA827A17800CE78887611F2F2455C9EA1F7E6F0F101C67CDEEF6D7F21E0D1D9295C2E9FA3191EE1B59CA4C82EFA658C39EC61B1854B08727E9BAEC92CE6707F6B57BC7E64490618DEB871D839B73339E8FC8737B5C2249F459A8243F1D1D44CC7F00164DA146DAFE8445B8C89999729449624AB7ADAF37F6B57BC7E64490611E7FA7ABCAF51C92176DF2183F8FC7C08794E14F7ADDB10D8941B15DA834481F9449624AB7ADAF372E808ACE2090B5E1725E5C173C3A84C3C5EA940A35A165FF2DBA43225CD8A89F83C798A30B85E16B6D8C47C27EEC5E9FB5C8C57E37DE458BEDA766A37F9254B7 X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CD0035DD76F8A8A4F6FE0C4520704E7AA1B33BD6F14CDC96F9C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF0417BEADF48D1460699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D343D1F112031EF3D626337B3544CF759754B4777EEBF277ADB9C096E753496F7B2172910C14339E22B1D7E09C32AA3244CF35423D3EB1E4ACABB481F9B529870D6BBA718C7E6A9E042FACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojyO2lHpuZu4QJpajw62IA2A== X-Mailru-Sender: 689FA8AB762F73936BC43F508A06382205CC686EE825C8DAD8D4A48660FDD52F83D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v5 21/52] sql: introduce bitwise operations for MEM X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mergen Imeev via Tarantool-patches Reply-To: imeevma@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" 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 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]<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; }