[Tarantool-patches] [PATCH v1 3/7] sql: rework OP_Seek* opcodes
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Thu Aug 5 01:25:49 MSK 2021
Thanks for the patch!
See 3 comments below.
> diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
> index 47a940c56..5d1d7592e 100644
> --- a/src/box/sql/mem.h
> +++ b/src/box/sql/mem.h
> @@ -1028,3 +1028,20 @@ mpstream_encode_vdbe_mem(struct mpstream *stream, struct Mem *var);
> char *
> sql_vdbe_mem_encode_tuple(struct Mem *fields, uint32_t field_count,
> uint32_t *tuple_size, struct region *region);
> +
> +static inline bool
> +is_mem_num_min(const struct Mem *mem)
> +{
> + return (mem->field_type == FIELD_TYPE_INTEGER &&
> + mem->type == MEM_TYPE_INT && mem->u.i == INT64_MIN) ||
> + (mem->field_type == FIELD_TYPE_UNSIGNED &&
> + mem->type == MEM_TYPE_UINT && mem->u.u == 0);
> +}
> +
> +static inline bool
> +is_mem_num_max(const struct Mem *mem)
1. Could you please name them to mem_is_num_min() and mem_is_num_max()?
Also what if they are DOUBLE? Should't these functions be called then
mem_is_int_min() and mem_is_int_max()?
> +{
> + return (mem->field_type == FIELD_TYPE_INTEGER ||
> + mem->field_type == FIELD_TYPE_UNSIGNED) &&
> + mem->type == MEM_TYPE_UINT && mem->u.u == 0;
> +}
> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 62f58def9..a69402720 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -2577,6 +2526,62 @@ case OP_Close: {
> *
> * See also: Found, NotFound, SeekGt, SeekGe, SeekLe
> */
> +case OP_SeekLT: { /* jump, in3 */
> + struct VdbeCursor *cur = p->apCsr[pOp->p1];
> +#ifdef SQL_DEBUG
> + cur->seekOp = pOp->opcode;
> +#endif
> + cur->nullRow = 0;
> + cur->uc.pCursor->iter_type = ITER_LT;
> +
> + uint32_t len = pOp->p4.i;
> + assert(pOp->p4type == P4_INT32);
> + assert(len <= cur->key_def->part_count);
> + struct Mem *mems = &aMem[pOp->p3];
> + bool is_le = false;
> + bool is_zero = false;
> + for (uint32_t i = 0; i < len; ++i) {
> + enum field_type type = cur->key_def->parts[i].type;
> + struct Mem *mem = &mems[i];
> + if (mem_is_field_compatible(mem, type))
> + continue;
> + if (!sql_type_is_numeric(type) || !mem_is_num(mem)) {
> + diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> + mem_str(mem), field_type_strs[type]);
> + goto abort_due_to_error;
> + }
> + int cmp = mem_cast_implicit_number(mem, type);
> + is_le = is_le || cmp > 0;
> + /*
> + * If number before cast were less than min possible for given
> + * field type, than there is no point to use iterator since we
> + * won't find anything.
> + */
> + is_zero = is_zero || (is_mem_num_min(mem) && cmp < 0);
2. Do you really need this optimization? Seems like a very rare case. The
same in the other places.
Also it looks like a lot of code duplication. But I see why, and again I
don't see a way to reuse all this code easily.
> + }
> + if (is_zero) {
> + assert(pOp->p2 > 0);
> + VdbeBranchTaken(1, 2);
> + goto jump_to_p2;
> + }
<...>
> +case OP_SeekLE: { /* jump, in3 */
<...>
> + cur->nullRow = 0;
> + bool is_eq = (cur->uc.pCursor->hints & OPFLAG_SEEKEQ) != 0;
> + cur->uc.pCursor->iter_type = is_eq ? ITER_REQ : ITER_LE;
> + assert(!is_eq || pOp[1].opcode == OP_IdxLT);
> +
> + uint32_t len = pOp->p4.i;
> + assert(pOp->p4type == P4_INT32);
> + assert(len <= cur->key_def->part_count);
> + struct Mem *mems = &aMem[pOp->p3];
> + bool is_lt = false;
> + bool is_zero = false;
> + for (uint32_t i = 0; i < len; ++i) {
> + enum field_type type = cur->key_def->parts[i].type;
> + struct Mem *mem = &mems[i];
> + if (mem_is_field_compatible(mem, type))
> + continue;
> + if (!sql_type_is_numeric(type) || !mem_is_num(mem)) {
> + diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> + mem_str(mem), field_type_strs[type]);
> + goto abort_due_to_error;
> }
> - iKey = i;
> -
> - /* If the P3 value could not be converted into an integer without
> - * loss of information, then special processing is required...
> + int cmp = mem_cast_implicit_number(mem, type);
> + is_lt = is_lt || cmp < 0;
3. You needed to find values <= mem. The mem during cast was
turned into mem2 < mem, correct? Then you need to find values
<= mem2. Otherwise you skip mem2 itself. Or am I mistaken
somewhere? Similar questions to all the other usages of
mem_cast_implicit_number for seeking.
More information about the Tarantool-patches
mailing list