From: Mergen Imeev via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Cc: tarantool-patches@dev.tarantool.org Subject: Re: [Tarantool-patches] [PATCH v2 4/4] sql: introduce mem_cmp_msgpack() Date: Sun, 11 Jul 2021 20:59:16 +0300 [thread overview] Message-ID: <20210711175916.GB99369@tarantool.org> (raw) In-Reply-To: <20c6c37d-6364-8fdb-0aa5-c7c82407b143@tarantool.org> Thank you for the review! My answers, diff and new patch below. On Sun, Jul 11, 2021 at 05:05:38PM +0200, Vladislav Shpilevoy wrote: > Thanks for the patch! > > See 4 comments below. > > On 10.07.2021 16:33, Mergen Imeev via Tarantool-patches wrote: > > This patch introduces the mem_cmp_scalar() function that compares MEM > > 1. scalar -> msgpack. > Thanks, fixed. > > diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c > > index 576596c9f..471b69a18 100644 > > --- a/src/box/sql/mem.c > > +++ b/src/box/sql/mem.c > > @@ -2073,35 +2073,72 @@ mem_cmp_scalar(const struct Mem *a, const struct Mem *b, int *result, > > <...> > > > - > > -/* > > - * The input pBlob is guaranteed to be a Blob that is not marked > > - * with MEM_Zero. Return true if it could be a zero-blob. > > - */ > > -static int > > -isAllZero(const char *z, int n) > > +int > > +mem_cmp_msgpack(const struct Mem *a, const char *b, int *result, > > + const struct coll *coll) > > 2. Maybe better make the function return 'b' after decoding via > making it an out parameter. So as the caller could save mp_next() > call. > Agree. Done. Also, I could use here mp_decode_str()/mp_decode_bin() instead of mp_decode_strl()/mp_decode_binl() but decided to do this when I will change struct Mem according to discussion. Hope, I won't forget about this. > > { > > - int i; > > - for (i = 0; i < n; i++) { > > - if (z[i]) > > - return 0; > > + struct Mem mem; > > + switch (mp_typeof(*b)) { > > + case MP_NIL: > > + mem.type = MEM_TYPE_NULL; > > + break; > > + case MP_BOOL: > > + mem.type = MEM_TYPE_BOOL; > > + mem.u.b = mp_decode_bool(&b); > > + break; > > + case MP_UINT: > > + mem.type = MEM_TYPE_UINT; > > + mem.u.u = mp_decode_uint(&b); > > + break; > > + case MP_INT: > > + mem.type = MEM_TYPE_INT; > > + mem.u.i = mp_decode_int(&b); > > + break; > > + case MP_FLOAT: > > + mem.type = MEM_TYPE_DOUBLE; > > + mem.u.r = mp_decode_float(&b); > > + break; > > + case MP_DOUBLE: > > + mem.type = MEM_TYPE_DOUBLE; > > + mem.u.r = mp_decode_double(&b); > > + break; > > + case MP_STR: > > + mem.type = MEM_TYPE_STR; > > + mem.n = mp_decode_strl(&b); > > + mem.z = (char *)b; > > + mem.flags = MEM_Ephem; > > + break; > > + case MP_BIN: > > + mem.type = MEM_TYPE_BIN; > > + mem.n = mp_decode_binl(&b); > > + mem.z = (char *)b; > > 3. Shouldn't this also have MEM_Ephem? > Fixed here and below. > > + break; > > + case MP_ARRAY: > > + case MP_MAP: > > + *result = -1; > > + return 0; > > + case MP_EXT: { > > + int8_t type; > > + const char *buf = b; > > + uint32_t len = mp_decode_extl(&b, &type); > > + if (type == MP_UUID) { > > + assert(len == UUID_LEN); > > + mem.type = MEM_TYPE_UUID; > > + b = buf; > > 4. You can decode &buf below without changing b. > I changed a bit this part. > > + if (mp_decode_uuid(&b, &mem.u.uuid) == NULL) > > + return -1; > > + break; > > + } > > + b += len; > > + mem.type = MEM_TYPE_BIN; > > + mem.z = (char *)buf; > > + mem.n = b - buf; > > + break; > > } > > - return 1; > > + default: > > + unreachable(); > > + } > > + return mem_cmp_scalar(a, &mem, result, coll); > > } Diff: diff --git a/src/box/sql.c b/src/box/sql.c index 7f24bd778..a5afcfabb 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -768,13 +768,12 @@ tarantoolsqlIdxKeyCompare(struct BtCursor *cursor, struct key_part *part = &unpacked->key_def->parts[i]; struct Mem *mem = unpacked->aMem + i; struct coll *coll = part->coll; - mem_cmp_msgpack(mem, p, &rc, coll); + mem_cmp_msgpack(mem, &p, &rc, coll); if (rc != 0) { if (part->sort_order == SORT_ORDER_ASC) rc = -rc; goto out; } - mp_next(&p); } rc = unpacked->default_rc; out: diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index 5e7b1f28b..4062ff4b3 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -2078,65 +2078,71 @@ mem_cmp_scalar(const struct Mem *a, const struct Mem *b, int *result, } int -mem_cmp_msgpack(const struct Mem *a, const char *b, int *result, +mem_cmp_msgpack(const struct Mem *a, const char **b, int *result, const struct coll *coll) { struct Mem mem; - switch (mp_typeof(*b)) { + switch (mp_typeof(**b)) { case MP_NIL: mem.type = MEM_TYPE_NULL; + mp_decode_nil(b); break; case MP_BOOL: mem.type = MEM_TYPE_BOOL; - mem.u.b = mp_decode_bool(&b); + mem.u.b = mp_decode_bool(b); break; case MP_UINT: mem.type = MEM_TYPE_UINT; - mem.u.u = mp_decode_uint(&b); + mem.u.u = mp_decode_uint(b); break; case MP_INT: mem.type = MEM_TYPE_INT; - mem.u.i = mp_decode_int(&b); + mem.u.i = mp_decode_int(b); break; case MP_FLOAT: mem.type = MEM_TYPE_DOUBLE; - mem.u.r = mp_decode_float(&b); + mem.u.r = mp_decode_float(b); break; case MP_DOUBLE: mem.type = MEM_TYPE_DOUBLE; - mem.u.r = mp_decode_double(&b); + mem.u.r = mp_decode_double(b); break; case MP_STR: mem.type = MEM_TYPE_STR; - mem.n = mp_decode_strl(&b); - mem.z = (char *)b; + mem.n = mp_decode_strl(b); + mem.z = (char *)*b; + *b += mem.n; mem.flags = MEM_Ephem; break; case MP_BIN: mem.type = MEM_TYPE_BIN; - mem.n = mp_decode_binl(&b); - mem.z = (char *)b; + mem.n = mp_decode_binl(b); + mem.z = (char *)*b; + *b += mem.n; + mem.flags = MEM_Ephem; break; case MP_ARRAY: case MP_MAP: + mp_next(b); *result = -1; return 0; case MP_EXT: { int8_t type; - const char *buf = b; - uint32_t len = mp_decode_extl(&b, &type); + const char *buf = *b; + uint32_t len = mp_decode_extl(&buf, &type); if (type == MP_UUID) { assert(len == UUID_LEN); mem.type = MEM_TYPE_UUID; - b = buf; - if (mp_decode_uuid(&b, &mem.u.uuid) == NULL) + if (mp_decode_uuid(b, &mem.u.uuid) == NULL) return -1; break; } - b += len; + len += buf - *b; mem.type = MEM_TYPE_BIN; - mem.z = (char *)buf; - mem.n = b - buf; + mem.z = (char *)*b; + mem.n = len; + mem.flags = MEM_Ephem; + *b += len; break; } default: @@ -2584,13 +2590,12 @@ sqlVdbeRecordCompareMsgpack(const void *key1, struct key_part *part = &key2->key_def->parts[i]; struct Mem *mem = key2->aMem + i; struct coll *coll = part->coll; - mem_cmp_msgpack(mem, key1, &rc, coll); + mem_cmp_msgpack(mem, (const char **)&key1, &rc, coll); if (rc != 0) { if (part->sort_order != SORT_ORDER_ASC) return rc; return -rc; } - mp_next((const char **)&key1); } key2->eqSeen = 1; diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h index 2439fd93b..c73536efb 100644 --- a/src/box/sql/mem.h +++ b/src/box/sql/mem.h @@ -706,11 +706,12 @@ mem_cmp_scalar(const struct Mem *a, const struct Mem *b, int *result, /** * Compare MEM and packed to msgpack value using SCALAR rules and return the - * result of comparison. Both values should be scalars. Original MEM and packed - * value are not changed. + * result of comparison. Both values should be scalars. Original MEM is not + * changed. If successful, the second argument will contain the address + * following the specified packed value. */ int -mem_cmp_msgpack(const struct Mem *a, const char *b, int *result, +mem_cmp_msgpack(const struct Mem *a, const char **b, int *result, const struct coll *coll); /** New patch: commit aa422cd2f19813503664e7292dbd01e7b0711a7d Author: Mergen Imeev <imeevma@gmail.com> Date: Fri Jul 9 11:59:34 2021 +0300 sql: introduce mem_cmp_msgpack() This patch introduces the mem_cmp_msgpack() function that compares MEM and packed to msgpack value using SCALAR rules. MEM and packed value must be scalars. Prior to this patch, there was a function that used SCALAR rules to compare MEM and packed value, but its design became overly complex as new types appeared. Closes #6164 diff --git a/src/box/sql.c b/src/box/sql.c index 790ca7f70..a5afcfabb 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -765,10 +765,12 @@ tarantoolsqlIdxKeyCompare(struct BtCursor *cursor, } } next_fieldno = fieldno + 1; - rc = sqlVdbeCompareMsgpack(&p, unpacked, i); + struct key_part *part = &unpacked->key_def->parts[i]; + struct Mem *mem = unpacked->aMem + i; + struct coll *coll = part->coll; + mem_cmp_msgpack(mem, &p, &rc, coll); if (rc != 0) { - if (unpacked->key_def->parts[i].sort_order != - SORT_ORDER_ASC) + if (part->sort_order == SORT_ORDER_ASC) rc = -rc; goto out; } diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index da27cd191..4062ff4b3 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -2077,35 +2077,78 @@ mem_cmp_scalar(const struct Mem *a, const struct Mem *b, int *result, return 0; } -/* - * Both *pMem1 and *pMem2 contain string values. Compare the two values - * using the collation sequence pColl. As usual, return a negative , zero - * or positive value if *pMem1 is less than, equal to or greater than - * *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". - * - * Strungs assume to be UTF-8 encoded - */ -static int -vdbeCompareMemString(const Mem * pMem1, const Mem * pMem2, - const struct coll * pColl) -{ - return pColl->cmp(pMem1->z, (size_t)pMem1->n, - pMem2->z, (size_t)pMem2->n, pColl); -} - -/* - * The input pBlob is guaranteed to be a Blob that is not marked - * with MEM_Zero. Return true if it could be a zero-blob. - */ -static int -isAllZero(const char *z, int n) -{ - int i; - for (i = 0; i < n; i++) { - if (z[i]) - return 0; +int +mem_cmp_msgpack(const struct Mem *a, const char **b, int *result, + const struct coll *coll) +{ + struct Mem mem; + switch (mp_typeof(**b)) { + case MP_NIL: + mem.type = MEM_TYPE_NULL; + mp_decode_nil(b); + break; + case MP_BOOL: + mem.type = MEM_TYPE_BOOL; + mem.u.b = mp_decode_bool(b); + break; + case MP_UINT: + mem.type = MEM_TYPE_UINT; + mem.u.u = mp_decode_uint(b); + break; + case MP_INT: + mem.type = MEM_TYPE_INT; + mem.u.i = mp_decode_int(b); + break; + case MP_FLOAT: + mem.type = MEM_TYPE_DOUBLE; + mem.u.r = mp_decode_float(b); + break; + case MP_DOUBLE: + mem.type = MEM_TYPE_DOUBLE; + mem.u.r = mp_decode_double(b); + break; + case MP_STR: + mem.type = MEM_TYPE_STR; + mem.n = mp_decode_strl(b); + mem.z = (char *)*b; + *b += mem.n; + mem.flags = MEM_Ephem; + break; + case MP_BIN: + mem.type = MEM_TYPE_BIN; + mem.n = mp_decode_binl(b); + mem.z = (char *)*b; + *b += mem.n; + mem.flags = MEM_Ephem; + break; + case MP_ARRAY: + case MP_MAP: + mp_next(b); + *result = -1; + return 0; + case MP_EXT: { + int8_t type; + const char *buf = *b; + uint32_t len = mp_decode_extl(&buf, &type); + if (type == MP_UUID) { + assert(len == UUID_LEN); + mem.type = MEM_TYPE_UUID; + if (mp_decode_uuid(b, &mem.u.uuid) == NULL) + return -1; + break; + } + len += buf - *b; + mem.type = MEM_TYPE_BIN; + mem.z = (char *)*b; + mem.n = len; + mem.flags = MEM_Ephem; + *b += len; + break; } - return 1; + default: + unreachable(); + } + return mem_cmp_scalar(a, &mem, result, coll); } char * @@ -2534,183 +2577,6 @@ sql_vdbemem_finalize(struct Mem *mem, struct func *func) return ctx.is_aborted ? -1 : 0; } -int -sqlVdbeCompareMsgpack(const char **key1, - struct UnpackedRecord *unpacked, int key2_idx) -{ - const char *aKey1 = *key1; - Mem *pKey2 = unpacked->aMem + key2_idx; - Mem mem1; - int rc = 0; - switch (mp_typeof(*aKey1)) { - default:{ - /* FIXME */ - rc = -1; - break; - } - case MP_NIL:{ - rc = -(pKey2->type != MEM_TYPE_NULL); - mp_decode_nil(&aKey1); - break; - } - case MP_BOOL:{ - mem1.u.b = mp_decode_bool(&aKey1); - if (pKey2->type == MEM_TYPE_BOOL) { - if (mem1.u.b != pKey2->u.b) - rc = mem1.u.b ? 1 : -1; - } else { - rc = pKey2->type == MEM_TYPE_NULL ? 1 : -1; - } - break; - } - case MP_UINT:{ - mem1.u.u = mp_decode_uint(&aKey1); - if (pKey2->type == MEM_TYPE_INT) { - rc = +1; - } else if (pKey2->type == MEM_TYPE_UINT) { - if (mem1.u.u < pKey2->u.u) - rc = -1; - else if (mem1.u.u > pKey2->u.u) - rc = +1; - } else if (pKey2->type == MEM_TYPE_DOUBLE) { - rc = double_compare_uint64(pKey2->u.r, - mem1.u.u, -1); - } else if (pKey2->type == MEM_TYPE_NULL) { - rc = 1; - } else if (pKey2->type == MEM_TYPE_BOOL) { - rc = 1; - } else { - rc = -1; - } - break; - } - case MP_INT:{ - mem1.u.i = mp_decode_int(&aKey1); - if (pKey2->type == MEM_TYPE_UINT) { - rc = -1; - } else if (pKey2->type == MEM_TYPE_INT) { - if (mem1.u.i < pKey2->u.i) { - rc = -1; - } else if (mem1.u.i > pKey2->u.i) { - rc = +1; - } - } else if (pKey2->type == MEM_TYPE_DOUBLE) { - rc = double_compare_nint64(pKey2->u.r, mem1.u.i, - -1); - } else if (pKey2->type == MEM_TYPE_NULL) { - rc = 1; - } else if (pKey2->type == MEM_TYPE_BOOL) { - rc = 1; - } else { - rc = -1; - } - break; - } - case MP_FLOAT:{ - mem1.u.r = mp_decode_float(&aKey1); - goto do_float; - } - case MP_DOUBLE:{ - mem1.u.r = mp_decode_double(&aKey1); - do_float: - if (pKey2->type == MEM_TYPE_INT) { - rc = double_compare_nint64(mem1.u.r, pKey2->u.i, - 1); - } else if (pKey2->type == MEM_TYPE_UINT) { - rc = double_compare_uint64(mem1.u.r, - pKey2->u.u, 1); - } else if (pKey2->type == MEM_TYPE_DOUBLE) { - if (mem1.u.r < pKey2->u.r) { - rc = -1; - } else if (mem1.u.r > pKey2->u.r) { - rc = +1; - } - } else if (pKey2->type == MEM_TYPE_NULL) { - rc = 1; - } else if (pKey2->type == MEM_TYPE_BOOL) { - rc = 1; - } else { - rc = -1; - } - break; - } - case MP_STR:{ - if (pKey2->type == MEM_TYPE_STR) { - struct key_def *key_def = unpacked->key_def; - mem1.n = mp_decode_strl(&aKey1); - mem1.z = (char *)aKey1; - aKey1 += mem1.n; - struct coll *coll = - key_def->parts[key2_idx].coll; - if (coll != NULL) { - mem1.type = MEM_TYPE_STR; - mem1.flags = 0; - rc = vdbeCompareMemString(&mem1, pKey2, - coll); - } else { - goto do_bin_cmp; - } - } else { - rc = pKey2->type == MEM_TYPE_BIN ? -1 : +1; - } - break; - } - case MP_BIN:{ - mem1.n = mp_decode_binl(&aKey1); - mem1.z = (char *)aKey1; - aKey1 += mem1.n; - do_blob: - if (pKey2->type == MEM_TYPE_BIN) { - if (pKey2->flags & MEM_Zero) { - if (!isAllZero - ((const char *)mem1.z, mem1.n)) { - rc = 1; - } else { - rc = mem1.n - pKey2->u.nZero; - } - } else { - int nCmp; - do_bin_cmp: - nCmp = MIN(mem1.n, pKey2->n); - rc = memcmp(mem1.z, pKey2->z, nCmp); - if (rc == 0) - rc = mem1.n - pKey2->n; - } - } else { - rc = 1; - } - break; - } - case MP_ARRAY: - case MP_MAP: { - mem1.z = (char *)aKey1; - mp_next(&aKey1); - mem1.n = aKey1 - (char *)mem1.z; - goto do_blob; - } - case MP_EXT: { - int8_t type; - const char *buf = aKey1; - uint32_t len = mp_decode_extl(&aKey1, &type); - if (type == MP_UUID) { - assert(len == UUID_LEN); - mem1.type = MEM_TYPE_UUID; - aKey1 = buf; - if (mp_decode_uuid(&aKey1, &mem1.u.uuid) == NULL || - mem_cmp_uuid(&mem1, pKey2, &rc) != 0) - rc = 1; - break; - } - aKey1 += len; - mem1.z = (char *)buf; - mem1.n = aKey1 - buf; - goto do_blob; - } - } - *key1 = aKey1; - return rc; -} - int sqlVdbeRecordCompareMsgpack(const void *key1, struct UnpackedRecord *key2) @@ -2721,13 +2587,14 @@ sqlVdbeRecordCompareMsgpack(const void *key1, n = MIN(n, key2->nField); for (i = 0; i != n; i++) { - rc = sqlVdbeCompareMsgpack((const char**)&key1, key2, i); + struct key_part *part = &key2->key_def->parts[i]; + struct Mem *mem = key2->aMem + i; + struct coll *coll = part->coll; + mem_cmp_msgpack(mem, (const char **)&key1, &rc, coll); if (rc != 0) { - if (key2->key_def->parts[i].sort_order != - SORT_ORDER_ASC) { - rc = -rc; - } - return rc; + if (part->sort_order != SORT_ORDER_ASC) + return rc; + return -rc; } } diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h index bbb99c4d2..c73536efb 100644 --- a/src/box/sql/mem.h +++ b/src/box/sql/mem.h @@ -704,6 +704,16 @@ int mem_cmp_scalar(const struct Mem *a, const struct Mem *b, int *result, const struct coll *coll); +/** + * Compare MEM and packed to msgpack value using SCALAR rules and return the + * result of comparison. Both values should be scalars. Original MEM is not + * changed. If successful, the second argument will contain the address + * following the specified packed value. + */ +int +mem_cmp_msgpack(const struct Mem *a, const char **b, int *result, + const struct coll *coll); + /** * 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 @@ -981,20 +991,6 @@ int sqlVdbeMemTooBig(Mem *); int sql_vdbemem_finalize(struct Mem *mem, struct func *func); -/** MEM and msgpack functions. */ - -/** - * Perform comparison of two keys: one is packed and one is not. - * - * @param key1 Pointer to pointer to first key. - * @param unpacked Pointer to unpacked tuple. - * @param key2_idx index of key in umpacked record to compare. - * - * @retval +1 if key1 > pUnpacked[iKey2], -1 ptherwise. - */ -int sqlVdbeCompareMsgpack(const char **key1, - struct UnpackedRecord *unpacked, int key2_idx); - /** * Perform comparison of two tuples: unpacked (key1) and packed (key2) * diff --git a/test/sql-tap/gh-6164-uuid-follow-ups.test.lua b/test/sql-tap/gh-6164-uuid-follow-ups.test.lua index 6b4a811c3..dd041c0b4 100755 --- a/test/sql-tap/gh-6164-uuid-follow-ups.test.lua +++ b/test/sql-tap/gh-6164-uuid-follow-ups.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(8) +test:plan(9) -- Make sure that function quote() can work with uuid. test:do_execsql_test( @@ -76,6 +76,18 @@ test:do_execsql_test( 2 }) +box.execute([[DELETE FROM t;]]) + +box.execute([[INSERT INTO t VALUES (1, X'00'), (2, ?);]], {uuid1}) + +test:do_execsql_test( + "gh-6164-9", + [[ + SELECT i FROM t ORDER BY s; + ]], { + 1, 2 + }) + box.execute([[DROP TABLE t;]]) test:finish_test()
next prev parent reply other threads:[~2021-07-11 17:59 UTC|newest] Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-07-10 14:33 [Tarantool-patches] [PATCH v2 0/4] Follow ups for uuid introduction Mergen Imeev via Tarantool-patches 2021-07-10 14:33 ` [Tarantool-patches] [PATCH v2 1/4] sql: introduce uuid to quote() Mergen Imeev via Tarantool-patches 2021-07-10 14:33 ` [Tarantool-patches] [PATCH v2 2/4] sql: allow to bind uuid values Mergen Imeev via Tarantool-patches 2021-07-10 14:33 ` [Tarantool-patches] [PATCH v2 3/4] sql: introduce mem_cmp_scalar() Mergen Imeev via Tarantool-patches 2021-07-11 15:03 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-11 17:51 ` Mergen Imeev via Tarantool-patches 2021-07-12 21:06 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-13 8:04 ` Mergen Imeev via Tarantool-patches 2021-07-10 14:33 ` [Tarantool-patches] [PATCH v2 4/4] sql: introduce mem_cmp_msgpack() Mergen Imeev via Tarantool-patches 2021-07-11 15:05 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-11 17:59 ` Mergen Imeev via Tarantool-patches [this message] 2021-07-12 21:09 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-13 8:10 ` Mergen Imeev via Tarantool-patches 2021-07-13 20:39 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-14 6:51 ` Mergen Imeev via Tarantool-patches 2021-07-14 21:53 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-15 6:58 ` Mergen Imeev via Tarantool-patches 2021-07-15 20:44 ` [Tarantool-patches] [PATCH v2 0/4] Follow ups for uuid introduction Vladislav Shpilevoy via Tarantool-patches 2021-07-16 8:57 Mergen Imeev via Tarantool-patches 2021-07-16 8:57 ` [Tarantool-patches] [PATCH v2 4/4] sql: introduce mem_cmp_msgpack() Mergen Imeev via Tarantool-patches 2021-07-19 9:16 ` Timur Safin via Tarantool-patches 2021-07-19 10:07 ` 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=20210711175916.GB99369@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=imeevma@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH v2 4/4] sql: introduce mem_cmp_msgpack()' \ /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