Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Konstantin Osipov <kostja.osipov@gmail.com>,
	imeevma@tarantool.org, tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH v1 1/1] sql: introduce operator []
Date: Sun, 21 Nov 2021 16:53:54 +0100	[thread overview]
Message-ID: <684c473b-33ff-11e9-b6b2-0362cc24190f@tarantool.org> (raw)
In-Reply-To: <20211119172502.GA136743@starling>

Thanks for the patch!

See 8 comments below.

>> @TarantoolBot document
>> Title: Operator [] in SQL
>>
>> Operator [] allows to get elements of MAP, ARRAY and ANY values.
>>
>> Rules for operator []:
>> 1) operator applied to the value to the left of `[` ("left-value");
>> 2) if left-value is not MAP, ARRAY or ANY, an error is thrown;
>> 3) if there is no values between `[` and `]`, left-value is returned as
>>    the result;

1. Why isn't it an error? Did I understand correctly that you mean []
with nothing inside?

>> 4) if there is one value between `[` and `]` ("right-value"), the result
>>    is:
>>   a) if left-value is ANY and its primitive type is not MAP or ARRAY,
>>      the result is NULL;

2. Why not error? This looks a bit controversial with how hard the rules
for explicit and implict casts are.

>>   b) if the type or primitive type of left-value is ARRAY, and
>>      right-value is INTEGER and its value is greater than 0 and not
>>      greater than the number of elements in ARRAY, the result will be a
>>      value with right-value as the index, otherwise the result will be
>>      NULL;

3. What if the right-value is not an integer?

>>   c) if the type or primitive type of left-value is MAP and it contains
>>      right-value as one of its keys, the result is the value with
>>      right-value as the key in left-value, otherwise the result is NULL;
>> 5) if there is more than one value between `[` and `]` than
>>    left-value[a, b, c, ...] == left-value[a][b][c]... except it will
>>    return NULL, if any of the `[]` operators return NULL.
>>
>> diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
>> index 789d8906c..abf47b8ef 100644
>> --- a/src/box/sql/expr.c
>> +++ b/src/box/sql/expr.c
>> @@ -3461,6 +3461,30 @@ expr_code_map(struct Parse *parser, struct Expr *expr, int reg)
>>  	sqlVdbeAddOp3(vdbe, OP_Map, count, reg, values_reg);
>>  }
>>  
>> +static void
>> +expr_code_getitem(struct Parse *parser, struct Expr *expr, int reg)

4. The same as for the array/map patches - should be sql_expr_emit_... or
expr_emit - depending on what prefix will you choose to use everywhere.

>> +{
>> +	struct Vdbe *vdbe = parser->pVdbe;
>> +	struct ExprList *list = expr->x.pList;
>> +	assert(list != NULL);
>> diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
>> index cfb88bffe..195dfde2b 100644
>> --- a/src/box/sql/mem.c
>> +++ b/src/box/sql/mem.c
>> @@ -3107,6 +3107,65 @@ mem_encode_map(const struct Mem *mems, uint32_t count, uint32_t *size,
>>  	return map;
>>  }
>>  
>> +static int
>> +mp_getitem(const char **data, const struct Mem *key)
>> +{
>> +	if ((mp_typeof(**data) != MP_ARRAY && mp_typeof(**data) != MP_MAP)) {

5. Double (()). Need only one.

>> +		*data = NULL;
>> +		return 0;
>> +	}
>> +	const char *end = *data;
>> +	if (mp_typeof(**data) == MP_ARRAY) {
>> +		uint32_t size = mp_decode_array(data);
>> +		if (!mem_is_uint(key) || key->u.u == 0 || key->u.u > size) {
>> +			*data = NULL;
>> +			return 0;
>> +		}
>> +		for (uint32_t i = 0; i < key->u.u - 1; ++i)
>> +			mp_next(data);
>> +		return 0;
>> +	}
>> +	struct Mem mem;
>> +	mem_create(&mem);
>> +	uint32_t size = mp_decode_map(data);
>> +	for (uint32_t i = 0; i < size; ++i) {
>> +		uint32_t len;
>> +		if (mem_from_mp_ephemeral(&mem, *data, &len) != 0)
>> +			return -1;

6. Lets add mem_is_trivial() assertion. Since you do not destroy the mem.

>> +		*data += len;
>> +		assert(!mem_is_map(&mem) && !mem_is_array(&mem));
>> +		if (mem_cmp_scalar(&mem, key, NULL) == 0)
>> +			return 0;
>> +		mp_next(data);
>> +	}
>> diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
>> index db7fef71a..30922b7f6 100644
>> --- a/src/box/sql/parse.y
>> +++ b/src/box/sql/parse.y
>> @@ -1126,6 +1127,22 @@ expr(A) ::= CAST(X) LP expr(E) AS typedef(T) RP(Y). {
>>    sqlExprAttachSubtrees(pParse->db, A.pExpr, E.pExpr, 0);
>>  }
>>  
>> +expr(A) ::= expr(X) LB exprlist(Y) RB(E). {
>> +  struct Expr *expr = sql_expr_new_dequoted(pParse->db, TK_GETITEM, NULL);

7. sql_expr_new_anon().

>> +  if (expr == NULL) {
>> +    sql_expr_list_delete(pParse->db, Y);
>> +    pParse->is_aborted = true;
>> +    return;
>> +  }
>> +  Y = sql_expr_list_append(pParse->db, Y, X.pExpr);
>> +  expr->x.pList = Y;
>> +  expr->type = FIELD_TYPE_ANY;
>> +  sqlExprSetHeightAndFlags(pParse, expr);
>> +  A.pExpr = expr;
>> +  A.zStart = X.zStart;
>> +  A.zEnd = &E.z[E.n];
>> +}

8. I got an assertion fail.

box.cfg{listen = 3313}
s = box.schema.create_space('TEST', {format = {{'ID'}, {'VALUE'}}})
_ = s:create_index('pk')
s:replace{1, {[{key = 100}] = 200}}
box.execute('SELECT value[1] FROM test')

Assertion failed: (!mem_is_map(&mem) && !mem_is_array(&mem)), function mp_getitem, file /Users/gerold/Work/Repositories/tarantool/src/box/sql/mem.c, line 3136.

  reply	other threads:[~2021-11-21 15:53 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-19 14:44 Mergen Imeev via Tarantool-patches
2021-11-19 17:25 ` Konstantin Osipov via Tarantool-patches
2021-11-21 15:53   ` Vladislav Shpilevoy via Tarantool-patches [this message]
2021-11-30 15:20     ` Mergen Imeev via Tarantool-patches
2021-12-02 23:43       ` Vladislav Shpilevoy via Tarantool-patches
2021-11-24 11:56   ` Mergen Imeev 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=684c473b-33ff-11e9-b6b2-0362cc24190f@tarantool.org \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=imeevma@tarantool.org \
    --cc=kostja.osipov@gmail.com \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v1 1/1] sql: introduce operator []' \
    /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