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 42F2E6EC5B; Wed, 14 Apr 2021 01:58:39 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 42F2E6EC5B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1618354719; bh=1XmCeWBZV1g5AKUBMyF92ICWE2Z9UNipNwYliaAZnQ4=; h=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=DuM+oUUrqWusoMOuIhW8XshZTnZ+x5etAUANbfugrXSpvfCjJyGaI0fijip55ypyq 7a9X6Z3lb34xBxnHXQC0h4mG5+1hEFc10w3TC8IQBb1Y6Fm5g63S1iY9y2OBSb7iOx xWNGoX9HpIKun/+DJhNwm9T/u4KUkOdOqlHzqIVA= Received: from smtp35.i.mail.ru (smtp35.i.mail.ru [94.100.177.95]) (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 98DF36EC5B for ; Wed, 14 Apr 2021 01:58:35 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 98DF36EC5B Received: by smtp35.i.mail.ru with esmtpa (envelope-from ) id 1lWRzO-0005jV-LU; Wed, 14 Apr 2021 01:58:35 +0300 Date: Wed, 14 Apr 2021 01:58:33 +0300 To: Vladislav Shpilevoy Message-ID: <20210413225833.GA70385@tarantool.org> References: <8b70c648c1b907b04859cfc8bcef94870057bf9f.1617984948.git.imeevma@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92FFCB8E6708E7480D608FE24BC85426BB1B55F651FED8C70182A05F5380850403E9386A52AAFC191DFCFF20AD5F6B168761018F842966F1467E1CAF613438D56 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7F87C043BA75DB4CEEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637BE899A9B5C1209058638F802B75D45FF914D58D5BE9E6BC1A93B80C6DEB9DEE97C6FB206A91F05B235184873205BE9FC59780A141A118850EBA8952C4932A151D2E47CDBA5A96583C09775C1D3CA48CFED8438A78DFE0A9E117882F4460429724CE54428C33FAD30A8DF7F3B2552694AC26CFBAC0749D213D2E47CDBA5A9658378DA827A17800CE73AFA331E307B52169FA2833FD35BB23DF004C90652538430302FCEF25BFAB3454AD6D5ED66289B5278DA827A17800CE78B1055E99C449777D32BA5DBAC0009BE395957E7521B51C20BC6067A898B09E4090A508E0FED6299176DF2183F8FC7C02059237F47C255B9CD04E86FAF290E2D7E9C4E3C761E06A71DD303D21008E298D5E8D9A59859A8B6B372FE9A2E580EFC725E5C173C3A84C3727597FF642BA4D735872C767BF85DA2F004C90652538430E4A6367B16DE6309 X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A2368A440D3B0F6089093C9A16E5BC824A2A04A2ABAA09D25379311020FFC8D4ADD69086D7A80F17D3346C27DB7C03DF2F X-C1DE0DAB: 0D63561A33F958A5A4690CE1C311912B45C99258DB903F28D5D4498820D1CD05D59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA7502E6951B79FF9A3F410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3416EA6E382A5BB176E50CD0F9976B90ACDBFCB4006263D765B29E23B04E789EE38DF77CF9666C7B231D7E09C32AA3244C570E8B186FE0D517ED9483BFA7E7617B408A6A02710B7304FACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojnA7/qPBUIXGCp5a4Be+NWg== X-Mailru-Sender: 5C3750E245F362008BC1685FEC6306EDFB815675E1A65790DFCFF20AD5F6B168B67A942A63B4089A5105BD0848736F9966FEC6BF5C9C28D97E07721503EA2E00ED97202A5A4E92BF7402F9BA4338D657ED14614B50AE0675 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v5 39/52] sql: introduce mem_to_int*() functions 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: Mergen Imeev Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Thank you for the review! My answers, diff and new patch below. On Tue, Apr 13, 2021 at 01:39:01AM +0200, Vladislav Shpilevoy wrote: > Good job on the fixes! > > This is the last email for today, I will continue the review of > the patchset tomorrow. > > See 2 comments below. > > > diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c > > index 71a827034..e61ad4251 100644 > > --- a/src/box/sql/vdbe.c > > +++ b/src/box/sql/vdbe.c > > @@ -1432,17 +1432,14 @@ case OP_AddImm: { /* in1 */ > > */ > > case OP_MustBeInt: { /* jump, in1 */ > > pIn1 = &aMem[pOp->p1]; > > - if (!mem_is_int(pIn1)) { > > - mem_apply_type(pIn1, FIELD_TYPE_INTEGER); > > - if (!mem_is_int(pIn1)) { > > - if (pOp->p2==0) { > > - diag_set(ClientError, ER_SQL_TYPE_MISMATCH, > > - mem_str(pIn1), "integer"); > > - goto abort_due_to_error; > > - } else { > > - goto jump_to_p2; > > - } > > - } > > + if (mem_is_int(pIn1)) > > 1. The same check is done inside mem_to_int_precise(). You > don't need to do it manually. > Thanks, fixed. > > + break; > > + if (mem_to_int_precise(pIn1) != 0) { > > + if (pOp->p2 !=0 ) > > 2. Whitespace should be before '0', not after. > Fixed. > > + goto jump_to_p2; > > + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, > > + mem_str(pIn1), "integer"); > > + goto abort_due_to_error; > > } > > break; > > } > > Diff: diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 061f77952..c908f13c0 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1435,10 +1435,8 @@ case OP_AddImm: { /* in1 */ */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; - if (mem_is_int(pIn1)) - break; if (mem_to_int_precise(pIn1) != 0) { - if (pOp->p2 !=0 ) + if (pOp->p2 != 0) goto jump_to_p2; diag_set(ClientError, ER_SQL_TYPE_MISMATCH, mem_str(pIn1), "integer"); New patch: commit ecf63aa8a6887b3b1ac7a67a6b60fe3a62426ed9 Author: Mergen Imeev Date: Wed Mar 17 10:46:29 2021 +0300 sql: introduce mem_to_int*() functions This patch introduces mem_to_int() and mem_to_int_precise() functions. These functions are used to convert a MEM to a MEM that contains integer value. These functions defines the rules that are used during convertion from values of all other types to INTEGER. Part of #5818 diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index 3930067e1..fd68acd6e 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -492,6 +492,90 @@ mem_set_null_clear(struct Mem *mem) mem->flags = MEM_Null | MEM_Cleared; } +static inline int +bytes_to_int(struct Mem *mem) +{ + bool is_neg; + int64_t i; + if (sql_atoi64(mem->z, &i, &is_neg, mem->n) != 0) + return -1; + mem_set_int(mem, i, is_neg); + return 0; +} + +static inline int +double_to_int(struct Mem *mem) +{ + double d = mem->u.r; + if (d < 0 && d >= (double)INT64_MIN) { + mem->u.i = (int64_t)d; + mem->flags = MEM_Int; + mem->field_type = FIELD_TYPE_INTEGER; + return 0; + } + if (d >= 0 && d < (double)UINT64_MAX) { + mem->u.u = (uint64_t)d; + mem->flags = MEM_UInt; + mem->field_type = FIELD_TYPE_UNSIGNED; + return 0; + } + return -1; +} + +static inline int +double_to_int_precise(struct Mem *mem) +{ + double d = mem->u.r; + if (d < 0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { + mem->u.i = (int64_t)d; + mem->flags = MEM_Int; + mem->field_type = FIELD_TYPE_INTEGER; + return 0; + } + if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + mem->u.u = (uint64_t)d; + mem->flags = MEM_UInt; + mem->field_type = FIELD_TYPE_UNSIGNED; + return 0; + } + return -1; +} + +static inline int +bool_to_int(struct Mem *mem) +{ + mem->u.u = (uint64_t)mem->u.b; + mem->flags = MEM_UInt; + mem->field_type = FIELD_TYPE_UNSIGNED; + return 0; +} + +int +mem_to_int(struct Mem *mem) +{ + if ((mem->flags & (MEM_Int | MEM_UInt)) != 0) + return 0; + if ((mem->flags & (MEM_Str | MEM_Blob)) != 0) + return bytes_to_int(mem); + if ((mem->flags & MEM_Real) != 0) + return double_to_int(mem); + if ((mem->flags & MEM_Bool) != 0) + return bool_to_int(mem); + return -1; +} + +int +mem_to_int_precise(struct Mem *mem) +{ + if ((mem->flags & (MEM_Int | MEM_UInt)) != 0) + return 0; + if ((mem->flags & MEM_Str) != 0) + return bytes_to_int(mem); + if ((mem->flags & MEM_Real) != 0) + return double_to_int_precise(mem); + return -1; +} + int mem_copy(struct Mem *to, const struct Mem *from) { @@ -1694,26 +1778,6 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type) } } -/* - * The MEM structure is already a MEM_Real. Try to also make it a - * MEM_Int if we can. - */ -int -mem_apply_integer_type(Mem *pMem) -{ - int rc; - i64 ix; - assert(pMem->flags & MEM_Real); - assert(EIGHT_BYTE_ALIGNMENT(pMem)); - - if ((rc = doubleToInt64(pMem->u.r, (int64_t *) &ix)) == 0) { - pMem->u.i = ix; - pMem->flags = pMem->u.r <= -1 ? MEM_Int : MEM_UInt; - pMem->field_type = FIELD_TYPE_INTEGER; - } - return rc; -} - /* * Add MEM_Str to the set of representations for the given Mem. Numbers * are converted using sql_snprintf(). Converting a BLOB to a string @@ -1985,34 +2049,6 @@ mem_convert_to_unsigned(struct Mem *mem) return 0; } -/** - * Convert the numeric value contained in MEM to integer. - * - * @param mem The MEM that contains the numeric value. - * @retval 0 if the conversion was successful, -1 otherwise. - */ -static int -mem_convert_to_integer(struct Mem *mem) -{ - if ((mem->flags & (MEM_UInt | MEM_Int)) != 0) - return 0; - if ((mem->flags & MEM_Real) == 0) - return -1; - double d = mem->u.r; - if (d >= (double)UINT64_MAX || d < (double)INT64_MIN) - return -1; - if (d < 0.) { - mem->u.i = (int64_t)d; - mem->flags = MEM_Int; - mem->field_type = FIELD_TYPE_INTEGER; - } else { - mem->u.u = (uint64_t)d; - mem->flags = MEM_UInt; - mem->field_type = FIELD_TYPE_UNSIGNED; - } - return 0; -} - int mem_convert_to_numeric(struct Mem *mem, enum field_type type) { @@ -2023,7 +2059,7 @@ mem_convert_to_numeric(struct Mem *mem, enum field_type type) if (type == FIELD_TYPE_UNSIGNED) return mem_convert_to_unsigned(mem); assert(type == FIELD_TYPE_INTEGER); - return mem_convert_to_integer(mem); + return mem_to_int(mem); } static int diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h index 9890762e0..5aabcc1fd 100644 --- a/src/box/sql/mem.h +++ b/src/box/sql/mem.h @@ -683,6 +683,24 @@ mem_cmp_str(const struct Mem *left, const struct Mem *right, int *result, int mem_cmp_num(const struct Mem *a, const struct Mem *b, int *result); +/** + * Convert the given MEM to INTEGER. This function and the function below define + * the rules that are used to convert values of all other types to INTEGER. In + * this function, the conversion from double to integer may result in loss of + * precision. + */ +int +mem_to_int(struct Mem *mem); + +/** + * Convert the given MEM to INTEGER. This function and the function above define + * the rules that are used to convert values of all other types to INTEGER. In + * this function, the conversion from double to integer is only possible if it + * is lossless. + */ +int +mem_to_int_precise(struct Mem *mem); + /** * Simple type to str convertor. It is used to simplify * error reporting. @@ -743,7 +761,6 @@ int vdbe_mem_numerify(struct Mem *mem); int sqlVdbeMemCast(struct Mem *, enum field_type type); -int mem_apply_integer_type(struct Mem *); int sqlVdbeMemStringify(struct Mem *); int sqlVdbeMemNulTerminate(struct Mem *); int sqlVdbeMemExpandBlob(struct Mem *); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index e07ff1be9..c908f13c0 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1435,17 +1435,12 @@ case OP_AddImm: { /* in1 */ */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; - if (!mem_is_int(pIn1)) { - mem_apply_type(pIn1, FIELD_TYPE_INTEGER); - if (!mem_is_int(pIn1)) { - if (pOp->p2==0) { - diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - mem_str(pIn1), "integer"); - goto abort_due_to_error; - } else { - goto jump_to_p2; - } - } + if (mem_to_int_precise(pIn1) != 0) { + if (pOp->p2 != 0) + goto jump_to_p2; + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + mem_str(pIn1), "integer"); + goto abort_due_to_error; } break; }