From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (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 C908B4696C3 for ; Sun, 8 Mar 2020 20:47:40 +0300 (MSK) From: Vladislav Shpilevoy Date: Sun, 8 Mar 2020 18:47:35 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH 3/3] box: introduce box_return_mp() public C function List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org, korablev@tarantool.org, imun@tarantool.org Closes #4641 @TarantoolBot document Title: box_return_mp() public C function Stored C functions could return a result only via `box_return_tuple()` function. That made users create a tuple every time they wanted to return something from a C function. Now public C API offers another way to return - `box_return_mp()`. It allows to return arbitrary MessagePack, not wrapped into a tuple object. This is simpler to use for small results like a number, boolean, or a short string. Besides, `box_return_mp()` is much faster than `box_return_tuple()`, especially for small MessagePack. Note, that it is faster only if an alternative is to create a tuple by yourself. If an already existing tuple was obtained from an iterator, and you want to return it, then of course it is faster to return via `box_return_tuple()`, than via extraction of tuple data, and calling `box_return_mp()`. Here is the function declaration from module.h: ```C /** * Return MessagePack from a stored C procedure. The MessagePack * is copied, so it is safe to free/reuse the passed arguments * after the call. * MessagePack is not validated, for the sake of speed. It is * expected to be a single encoded object. An attempt to encode * and return multiple objects without wrapping them into an * MP_ARRAY or MP_MAP is undefined behaviour. * * \param ctx An opaque structure passed to the stored C procedure * by Tarantool. * \param mp Begin of MessagePack. * \param mp_end End of MessagePack. * \retval -1 Error. * \retval 0 Success. */ API_EXPORT int box_return_mp(box_function_ctx_t *ctx, const char *mp, const char *mp_end); ``` --- extra/exports | 1 + src/box/box.cc | 6 ++++++ src/box/box.h | 19 +++++++++++++++++++ test/box/function1.c | 37 +++++++++++++++++++++++++++++++++++++ test/box/function1.result | 31 +++++++++++++++++++++++++++++++ test/box/function1.test.lua | 14 ++++++++++++++ 6 files changed, 108 insertions(+) diff --git a/extra/exports b/extra/exports index 3a0637317..d793edfe4 100644 --- a/extra/exports +++ b/extra/exports @@ -205,6 +205,7 @@ box_tuple_extract_key box_tuple_compare box_tuple_compare_with_key box_return_tuple +box_return_mp box_space_id_by_name box_index_id_by_name box_select diff --git a/src/box/box.cc b/src/box/box.cc index 276430913..4e15f21fc 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -1073,6 +1073,12 @@ box_return_tuple(box_function_ctx_t *ctx, box_tuple_t *tuple) return port_c_add_tuple(ctx->port, tuple); } +int +box_return_mp(box_function_ctx_t *ctx, const char *mp, const char *mp_end) +{ + return port_c_add_mp(ctx->port, mp, mp_end); +} + /* schema_find_id()-like method using only public API */ uint32_t box_space_id_by_name(const char *name, uint32_t len) diff --git a/src/box/box.h b/src/box/box.h index f37a945eb..a23383630 100644 --- a/src/box/box.h +++ b/src/box/box.h @@ -284,6 +284,25 @@ typedef struct box_function_ctx box_function_ctx_t; API_EXPORT int box_return_tuple(box_function_ctx_t *ctx, box_tuple_t *tuple); +/** + * Return MessagePack from a stored C procedure. The MessagePack + * is copied, so it is safe to free/reuse the passed arguments + * after the call. + * MessagePack is not validated, for the sake of speed. It is + * expected to be a single encoded object. An attempt to encode + * and return multiple objects without wrapping them into an + * MP_ARRAY or MP_MAP is undefined behaviour. + * + * \param ctx An opaque structure passed to the stored C procedure + * by Tarantool. + * \param mp Begin of MessagePack. + * \param mp_end End of MessagePack. + * \retval -1 Error. + * \retval 0 Success. + */ +API_EXPORT int +box_return_mp(box_function_ctx_t *ctx, const char *mp, const char *mp_end); + /** * Find space id by name. * diff --git a/test/box/function1.c b/test/box/function1.c index 87062d6a8..48a561100 100644 --- a/test/box/function1.c +++ b/test/box/function1.c @@ -245,3 +245,40 @@ test_sleep(box_function_ctx_t *ctx, const char *args, const char *args_end) fiber_sleep(0); return 0; } + +int +test_return_mp(box_function_ctx_t *ctx, const char *args, const char *args_end) +{ + (void) args; + (void) args_end; + char buf[512]; + char *pos = mp_encode_uint(buf, 1); + int rc = box_return_mp(ctx, buf, pos); + if (rc != 0) + return rc; + + pos = mp_encode_int(buf, -1); + rc = box_return_mp(ctx, buf, pos); + if (rc != 0) + return rc; + + pos = mp_encode_uint(buf, UINT64_MAX); + rc = box_return_mp(ctx, buf, pos); + if (rc != 0) + return rc; + + const char *str = "123456789101112131415"; + pos = mp_encode_str(buf, str, strlen(str)); + rc = box_return_mp(ctx, buf, pos); + if (rc != 0) + return rc; + + pos = mp_encode_array(buf, 1); + pos = mp_encode_uint(pos, 2); + box_tuple_t *tuple = box_tuple_new(box_tuple_format_default(), + buf, pos); + if (tuple == NULL) + return -1; + rc = box_return_tuple(ctx, tuple); + return rc; +} diff --git a/test/box/function1.result b/test/box/function1.result index b91d63c51..301f666ef 100644 --- a/test/box/function1.result +++ b/test/box/function1.result @@ -791,6 +791,37 @@ box.schema.func.drop("function1.multireturn") --- ... -- +-- gh-4641: box_return_mp() C API to return arbitrary MessagePack +-- from C functions. +-- +name = 'function1.test_return_mp' +--- +... +box.schema.func.create(name, {language = "C", exports = {'LUA'}}) +--- +... +box.func[name]:call() +--- +- 1 +- -1 +- 18446744073709551615 +- '123456789101112131415' +- [2] +... +box.schema.user.grant('guest', 'super') +--- +... +net:connect(box.cfg.listen):call(name) +--- +- [1, -1, 18446744073709551615, '123456789101112131415', [2]] +... +box.schema.user.revoke('guest', 'super') +--- +... +box.schema.func.drop(name) +--- +... +-- -- gh-4182: Introduce persistent Lua functions. -- test_run:cmd("setopt delimiter ';'") diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua index b1841f3ad..670d63a44 100644 --- a/test/box/function1.test.lua +++ b/test/box/function1.test.lua @@ -268,6 +268,20 @@ box.schema.func.create('function1.multireturn', {language = "C", exports = {'LUA box.execute("SELECT \"function1.multireturn\"()") box.schema.func.drop("function1.multireturn") +-- +-- gh-4641: box_return_mp() C API to return arbitrary MessagePack +-- from C functions. +-- +name = 'function1.test_return_mp' +box.schema.func.create(name, {language = "C", exports = {'LUA'}}) +box.func[name]:call() + +box.schema.user.grant('guest', 'super') +net:connect(box.cfg.listen):call(name) +box.schema.user.revoke('guest', 'super') + +box.schema.func.drop(name) + -- -- gh-4182: Introduce persistent Lua functions. -- -- 2.21.1 (Apple Git-122.3)