Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: imeevma@tarantool.org, tsafin@tarantool.org
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH v5 20/52] sql: introduce mem_compare()
Date: Sun, 11 Apr 2021 20:16:30 +0200	[thread overview]
Message-ID: <85edf743-dd85-d4f7-2aad-05802ea67e9e@tarantool.org> (raw)
In-Reply-To: <5a71515faac5f305fc3bd1ebbc20d1dd65bf027c.1617984948.git.imeevma@gmail.com>

Nice fixes!

This is the last email for today, I will continue the review of
the patchset tomorrow.

See 6 comments below.

> diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
> index 859e337aa..eee72a7fe 100644
> --- a/src/box/sql/mem.c
> +++ b/src/box/sql/mem.c
> @@ -624,6 +624,211 @@ mem_rem(const struct Mem *left, const struct Mem *right, struct Mem *result)
>  	return 0;
>  }
>  
> +static int
> +compare_blobs(const struct Mem *a, const struct Mem *b, int *result)
> +{

1. Would be good to have an assertion here that both types are MEM_Blob.

> +	int an = a->n;
> +	int bn = b->n;
> +	int minlen = MIN(an, bn);
> +
> +	/*
> +	 * It is possible to have a Blob value that has some non-zero content
> +	 * followed by zero content.  But that only comes up for Blobs formed
> +	 * by the OP_MakeRecord opcode, and such Blobs never get passed into
> +	 * mem_compare().
> +	 */
> +	assert((a->flags & MEM_Zero) == 0 || an == 0);
> +	assert((b->flags & MEM_Zero) == 0 || bn == 0);
> +
> +	if ((a->flags & b->flags & MEM_Zero) != 0) {
> +		*result = a->u.nZero - b->u.nZero;
> +		return 0;
> +	}
> +	if ((a->flags & MEM_Zero) != 0) {
> +		for (int i = 0; i < minlen; ++i) {
> +			if (b->z[i] != 0) {
> +				*result = -1;
> +				return 0;
> +			}
> +		}
> +		*result = a->u.nZero - bn;
> +		return 0;
> +	}
> +	if ((b->flags & MEM_Zero) != 0) {
> +		for (int i = 0; i < minlen; ++i) {
> +			if (a->z[i] != 0){
> +				*result = 1;
> +				return 0;
> +			}
> +		}
> +		*result = b->u.nZero - an;
> +		return 0;
> +	}
> +	*result = memcmp(a->z, b->z, minlen);
> +	if (*result != 0)
> +		return 0;
> +	*result = an - bn;
> +	return 0;

2. compare_blobs never fails. So you can drop result out argument
and return the comparison result as 'return'.

> +}
> +
> +static int
> +compare_numbers(const struct Mem *left, const struct Mem *right, int *result)
> +{
> +	struct sql_num a, b;
> +	/* TODO: Here should be check for right value type. */

3. What if 'b' is a string, which can't be converted to a number?

> +	if (get_number(right, &b) != 0) {
> +		*result = -1;
> +		return 0;
> +	}
> +	if (get_number(left, &a) != 0) {> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH, mem_str(left),
> +			 "numeric");
> +		return -1;
> +	}
> +	if (a.type == MEM_Real) {
> +		if (b.type == MEM_Real) {
> +			if (a.d > b.d)
> +				*result = 1;
> +			else if (a.d < b.d)
> +				*result = -1;
> +			else
> +				*result = 0;
> +			return 0;
> +		}
> +		if (b.type == MEM_Int)
> +			*result = double_compare_nint64(a.d, b.i, 1);
> +		else
> +			*result = double_compare_uint64(a.d, b.u, 1);
> +		return 0;
> +	}
> +	if (a.type == MEM_Int) {
> +		if (b.type == MEM_Int) {
> +			if (a.i > b.i)
> +				*result = 1;
> +			else if (a.i < b.i)
> +				*result = -1;
> +			else
> +				*result = 0;
> +			return 0;
> +		}
> +		if (b.type == MEM_UInt)
> +			*result = -1;
> +		else
> +			*result = double_compare_nint64(b.d, a.i, -1);
> +		return 0;
> +	}
> +	assert(a.type == MEM_UInt);
> +	if (b.type == MEM_UInt) {
> +		if (a.u > b.u)
> +			*result = 1;
> +		else if (a.u < b.u)
> +			*result = -1;
> +		else
> +			*result = 0;
> +		return 0;
> +	}
> +	if (b.type == MEM_Int)
> +		*result = 1;
> +	else
> +		*result = double_compare_uint64(b.d, a.u, -1);
> +	return 0;
> +}
> +
> +static int
> +compare_strings(const struct Mem *left, const struct Mem *right, int *result,
> +		const struct coll *coll)
> +{
> +	char *a;
> +	uint32_t an;
> +	char bufl[BUF_SIZE];
> +	if ((left->flags & MEM_Str) != 0) {
> +		a = left->z;
> +		an = left->n;
> +	} else {
> +		assert((left->flags & (MEM_Int | MEM_UInt | MEM_Real)) != 0);
> +		a = &bufl[0];
> +		if ((left->flags & MEM_Int) != 0)
> +			sql_snprintf(BUF_SIZE, a, "%lld", left->u.i);
> +		else if ((left->flags & MEM_UInt) != 0)
> +			sql_snprintf(BUF_SIZE, a, "%llu", left->u.u);
> +		else
> +			sql_snprintf(BUF_SIZE, a, "%!.15g", left->u.r);
> +		an = strlen(a);
> +	}
> +
> +	char *b;
> +	uint32_t bn;
> +	char bufr[BUF_SIZE];
> +	if ((right->flags & MEM_Str) != 0) {
> +		b = right->z;
> +		bn = right->n;
> +	} else {
> +		assert((right->flags & (MEM_Int | MEM_UInt | MEM_Real)) != 0);
> +		b = &bufr[0];
> +		if ((right->flags & MEM_Int) != 0)
> +			sql_snprintf(BUF_SIZE, b, "%lld", right->u.i);
> +		else if ((right->flags & MEM_UInt) != 0)
> +			sql_snprintf(BUF_SIZE, b, "%llu", right->u.u);
> +		else
> +			sql_snprintf(BUF_SIZE, b, "%!.15g", right->u.r);
> +		bn = strlen(b);
> +	}
> +	if (coll) {
> +		*result = coll->cmp(a, an, b, bn, coll);
> +		return 0;
> +	}
> +	uint32_t minlen = MIN(an, bn);
> +	*result = memcmp(a, b, minlen);
> +	if (*result != 0)
> +		return 0;
> +	*result = an - bn;
> +	return 0;

4. It can't fail either. You can return result as 'return'.

> +}
> +
> +int
> +mem_compare(const struct Mem *left, const struct Mem *right, int *result,
> +	    enum field_type type, struct coll *coll)
> +{
> +	assert(((left->flags | right->flags) & MEM_Null) == 0);
> +	int flags_any = left->flags | right->flags;

5. 'any' isn't needed until the next branch. You can move it right above

	if ((flags_any & MEM_Bool) != 0) {

> +	int flags_all = left->flags & right->flags;
> +
> +	if ((flags_all & MEM_Bool) != 0) {
> +		if (left->u.b == right->u.b)
> +			*result = 0;
> +		else if (left->u.b)
> +			*result = 1;
> +		else
> +			*result = -1;
> +		return 0;
> +	}
> +	if ((flags_any & MEM_Bool) != 0) {
> +		char *str = (left->flags & MEM_Bool) == 0 ?
> +			    mem_type_to_str(left) : mem_type_to_str(right);
> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH, str, "boolean");
> +		return -1;
> +	}
> +
> +	if ((flags_all & MEM_Blob) != 0)
> +		return compare_blobs(left, right, result);
> +	if ((flags_any & MEM_Blob) != 0) {
> +		char *str = (left->flags & MEM_Blob) == 0 ?
> +			    mem_type_to_str(left) : mem_type_to_str(right);
> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH, str, "varbinary");
> +		return -1;
> +	}
> +
> +	if (type == FIELD_TYPE_STRING)
> +		return compare_strings(left, right, result, coll);
> +
> +	if (sql_type_is_numeric(type) ||
> +	    (flags_any & (MEM_Int | MEM_UInt | MEM_Real)) != 0)
> +		return compare_numbers(left, right, result);
> +
> +	assert((left->flags & MEM_Str) != 0 && (right->flags & MEM_Str) != 0);
> +	return compare_strings(left, right, result, coll);
> +}
> diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
> index 69a7d9f7a..6c022d8d8 100644
> --- a/src/box/sql/mem.h
> +++ b/src/box/sql/mem.h
> @@ -226,6 +226,11 @@ 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);
>  
> +/** Compare two non-NULL MEMs and return the result of comparison. */
> +int
> +mem_compare(const struct Mem *left, const struct Mem *right, int *result,
> +	    enum field_type type, struct coll *coll);

6. What is 'type'?

Can you keep it out of the comparator somehow? For example, make it
3 functions: mem_cmp_as_str, mem_cmp_as_num, and just a generic mem_cmp
without any types calling the first 2 comparators. Otherwise the type
thing is super ugly. It leaks the details of opcodes into mem.c.

  reply	other threads:[~2021-04-11 18:16 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-09 16:51 [Tarantool-patches] [PATCH v5 00/52] Move mem-related functions to mem.c/mem.h Mergen Imeev via Tarantool-patches
2021-04-09 16:51 ` [Tarantool-patches] [PATCH v5 01/52] sql: enhance vdbe_decode_msgpack_into_mem() Mergen Imeev via Tarantool-patches
2021-04-11 17:42   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 12:01     ` Mergen Imeev via Tarantool-patches
2021-04-13 12:12       ` Mergen Imeev via Tarantool-patches
2021-04-13 23:22       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 23:34         ` Mergen Imeev via Tarantool-patches
2021-04-09 16:51 ` [Tarantool-patches] [PATCH v5 02/52] sql: disable unused code in sql/analyze.c Mergen Imeev via Tarantool-patches
2021-04-09 16:51 ` [Tarantool-patches] [PATCH v5 03/52] sql: disable unused code in sql/legacy.c Mergen Imeev via Tarantool-patches
2021-04-09 16:51 ` [Tarantool-patches] [PATCH v5 04/52] sql: remove NULL-termination in OP_ResultRow Mergen Imeev via Tarantool-patches
2021-04-14 22:23   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 22:37     ` Mergen Imeev via Tarantool-patches
2021-04-09 16:51 ` [Tarantool-patches] [PATCH v5 05/52] sql: move MEM-related functions to mem.c/mem.h Mergen Imeev via Tarantool-patches
2021-04-09 16:59 ` [Tarantool-patches] [PATCH v5 06/52] sql: refactor port_vdbemem_*() functions Mergen Imeev via Tarantool-patches
2021-04-09 16:59 ` [Tarantool-patches] [PATCH v5 07/52] sql: remove unused MEM-related functions Mergen Imeev via Tarantool-patches
2021-04-09 16:59 ` [Tarantool-patches] [PATCH v5 08/52] sql: disable unused code in sql/vdbemem.c Mergen Imeev via Tarantool-patches
2021-04-09 16:59 ` [Tarantool-patches] [PATCH v5 09/52] sql: introduce mem_str() Mergen Imeev via Tarantool-patches
2021-04-11 17:44   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 12:36     ` Mergen Imeev via Tarantool-patches
2021-04-14 22:23       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 22:42         ` Mergen Imeev via Tarantool-patches
2021-04-09 16:59 ` [Tarantool-patches] [PATCH v5 10/52] sql: introduce mem_create() Mergen Imeev via Tarantool-patches
2021-04-09 17:36 ` [Tarantool-patches] [PATCH v5 11/52] sql: introduce mem_destroy() Mergen Imeev via Tarantool-patches
2021-04-11 17:46   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 12:42     ` Mergen Imeev via Tarantool-patches
2021-04-09 17:36 ` [Tarantool-patches] [PATCH v5 12/52] sql: introduce mem_is_*() functions() Mergen Imeev via Tarantool-patches
2021-04-11 17:59   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 16:09     ` Mergen Imeev via Tarantool-patches
2021-04-14 22:48       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 23:07         ` Mergen Imeev via Tarantool-patches
2021-04-09 17:36 ` [Tarantool-patches] [PATCH v5 13/52] sql: introduce mem_copy() Mergen Imeev via Tarantool-patches
2021-04-11 18:06   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 16:18     ` Mergen Imeev via Tarantool-patches
2021-04-09 17:36 ` [Tarantool-patches] [PATCH v5 14/52] sql: introduce mem_copy_as_ephemeral() Mergen Imeev via Tarantool-patches
2021-04-11 18:10   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 16:31     ` Mergen Imeev via Tarantool-patches
2021-04-09 17:37 ` [Tarantool-patches] [PATCH v5 15/52] sql: rework mem_move() Mergen Imeev via Tarantool-patches
2021-04-11 18:10   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 16:38     ` Mergen Imeev via Tarantool-patches
2021-04-09 17:57 ` [Tarantool-patches] [PATCH v5 16/52] sql: rework vdbe_decode_msgpack_into_mem() Mergen Imeev via Tarantool-patches
2021-04-09 17:57 ` [Tarantool-patches] [PATCH v5 17/52] sql: remove sql_column_to_messagepack() Mergen Imeev via Tarantool-patches
2021-04-14 22:58   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 23:14     ` Mergen Imeev via Tarantool-patches
2021-04-09 17:57 ` [Tarantool-patches] [PATCH v5 18/52] sql: introduce mem_concat() Mergen Imeev via Tarantool-patches
2021-04-11 18:11   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 16:57     ` Mergen Imeev via Tarantool-patches
2021-04-14 23:04       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 23:22         ` Mergen Imeev via Tarantool-patches
2021-04-09 17:57 ` [Tarantool-patches] [PATCH v5 19/52] sql: introduce arithmetic operations for MEM Mergen Imeev via Tarantool-patches
2021-04-11 18:13   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 17:06     ` Mergen Imeev via Tarantool-patches
2021-04-14 23:10       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 23:33         ` Mergen Imeev via Tarantool-patches
2021-04-09 17:57 ` [Tarantool-patches] [PATCH v5 20/52] sql: introduce mem_compare() Mergen Imeev via Tarantool-patches
2021-04-11 18:16   ` Vladislav Shpilevoy via Tarantool-patches [this message]
2021-04-13 18:33     ` Mergen Imeev via Tarantool-patches
2021-04-14 23:20       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-14 23:40         ` Mergen Imeev via Tarantool-patches
2021-04-09 18:11 ` [Tarantool-patches] [PATCH v5 21/52] sql: introduce bitwise operations for MEM Mergen Imeev via Tarantool-patches
2021-04-12 23:31   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 20:49     ` Mergen Imeev via Tarantool-patches
2021-04-09 18:11 ` [Tarantool-patches] [PATCH v5 22/52] sql: Initialize MEM in sqlVdbeAllocUnpackedRecord() Mergen Imeev via Tarantool-patches
2021-04-09 18:11 ` [Tarantool-patches] [PATCH v5 23/52] sql: introduce mem_set_null() Mergen Imeev via Tarantool-patches
2021-04-09 18:11 ` [Tarantool-patches] [PATCH v5 24/52] sql: introduce mem_set_int() Mergen Imeev via Tarantool-patches
2021-04-12 23:32   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 20:56     ` Mergen Imeev via Tarantool-patches
2021-04-09 18:11 ` [Tarantool-patches] [PATCH v5 25/52] sql: introduce mem_set_uint() Mergen Imeev via Tarantool-patches
2021-04-09 19:45 ` [Tarantool-patches] [PATCH v5 26/52] sql: move mem_set_bool() and mem_set_double() Mergen Imeev via Tarantool-patches
2021-04-09 19:45 ` [Tarantool-patches] [PATCH v5 27/52] sql: introduce mem_set_str_*() functions Mergen Imeev via Tarantool-patches
2021-04-12 23:34   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 21:36     ` Mergen Imeev via Tarantool-patches
2021-04-14 23:49       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-15  1:25         ` Mergen Imeev via Tarantool-patches
2021-04-09 19:45 ` [Tarantool-patches] [PATCH v5 28/52] sql: introduce mem_copy_str() and mem_copy_str0() Mergen Imeev via Tarantool-patches
2021-04-12 23:35   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:00     ` Mergen Imeev via Tarantool-patches
2021-04-14 23:54       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-15  0:30         ` Mergen Imeev via Tarantool-patches
2021-04-09 19:45 ` [Tarantool-patches] [PATCH v5 29/52] sql: introduce mem_set_bin_*() functions Mergen Imeev via Tarantool-patches
2021-04-09 19:45 ` [Tarantool-patches] [PATCH v5 30/52] sql: introduce mem_copy_bin() Mergen Imeev via Tarantool-patches
2021-04-12 23:36   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:06     ` Mergen Imeev via Tarantool-patches
2021-04-09 20:05 ` [Tarantool-patches] [PATCH v5 31/52] sql: introduce mem_set_zerobin() Mergen Imeev via Tarantool-patches
2021-04-09 20:05 ` [Tarantool-patches] [PATCH v5 32/52] sql: introduce mem_set_*() for map and array Mergen Imeev via Tarantool-patches
2021-04-12 23:36   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:08     ` Mergen Imeev via Tarantool-patches
2021-04-09 20:05 ` [Tarantool-patches] [PATCH v5 33/52] sql: introduce mem_set_invalid() Mergen Imeev via Tarantool-patches
2021-04-09 20:05 ` [Tarantool-patches] [PATCH v5 34/52] sql: refactor mem_set_ptr() Mergen Imeev via Tarantool-patches
2021-04-09 20:05 ` [Tarantool-patches] [PATCH v5 35/52] sql: introduce mem_set_frame() Mergen Imeev via Tarantool-patches
2021-04-12 23:37   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:19     ` Mergen Imeev via Tarantool-patches
2021-04-09 20:25 ` [Tarantool-patches] [PATCH v5 36/52] sql: introduce mem_set_agg() Mergen Imeev via Tarantool-patches
2021-04-12 23:37   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:46     ` Mergen Imeev via Tarantool-patches
2021-04-09 20:25 ` [Tarantool-patches] [PATCH v5 37/52] sql: introduce mem_set_null_clear() Mergen Imeev via Tarantool-patches
2021-04-12 23:38   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:50     ` Mergen Imeev via Tarantool-patches
2021-04-09 20:25 ` [Tarantool-patches] [PATCH v5 38/52] sql: move MEM flags to mem.c Mergen Imeev via Tarantool-patches
2021-04-13 20:42   ` Mergen Imeev via Tarantool-patches
2021-04-09 20:25 ` [Tarantool-patches] [PATCH v5 39/52] sql: introduce mem_to_int*() functions Mergen Imeev via Tarantool-patches
2021-04-12 23:39   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-13 22:58     ` Mergen Imeev via Tarantool-patches
2021-04-13 23:10       ` Mergen Imeev via Tarantool-patches
2021-04-09 20:26 ` [Tarantool-patches] [PATCH v5 40/52] sql: introduce mem_to_double() Mergen Imeev via Tarantool-patches
2021-04-13 23:21   ` Mergen Imeev via Tarantool-patches
2021-04-15  0:39 ` [Tarantool-patches] [PATCH v5 00/52] Move mem-related functions to mem.c/mem.h Vladislav Shpilevoy via Tarantool-patches
2021-04-15  6:49 ` Kirill Yukhin via Tarantool-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=85edf743-dd85-d4f7-2aad-05802ea67e9e@tarantool.org \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=imeevma@tarantool.org \
    --cc=tsafin@tarantool.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v5 20/52] sql: introduce mem_compare()' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox