From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (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 3A46746970E for ; Fri, 31 Jan 2020 10:43:47 +0300 (MSK) References: <374477cbe80079687eefc9cd0d90f890dcbaec24.1580401020.git.lvasiliev@tarantool.org> From: Leonid Vasiliev Message-ID: <2ef399cf-d68d-fdb4-8ffe-ab1ff0df44d7@tarantool.org> Date: Fri, 31 Jan 2020 10:43:45 +0300 MIME-Version: 1.0 In-Reply-To: <374477cbe80079687eefc9cd0d90f890dcbaec24.1580401020.git.lvasiliev@tarantool.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Subject: Re: [Tarantool-patches] [PATCH 2/2] Add the custom error type List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: alexander.turenko@tarantool.org Cc: tarantool-patches@dev.tarantool.org Hi. Small diff was added. diff --git a/src/box/error.cc b/src/box/error.cc index 2e01f33ee..f903b72ec 100644 --- a/src/box/error.cc +++ b/src/box/error.cc @@ -91,7 +91,8 @@ box_custom_error_set(const char *file, unsigned line, const char *custom, const char *reason) { struct error *e = BuildCustomError(file, line, custom); - strcpy(e->errmsg, reason); + strncpy(e->errmsg, reason, DIAG_ERRMSG_MAX); + e->errmsg[DIAG_ERRMSG_MAX - 1] = '\0'; diag_add_error(&fiber()->diag, e); return -1; } diff --git a/src/box/error.h b/src/box/error.h index fcb5a2a43..f5e72617c 100644 --- a/src/box/error.h +++ b/src/box/error.h @@ -283,7 +283,7 @@ public: const char* custom_type() { - return m_custom_type ?: "(nil)"; + return m_custom_type; } private: /** Custom type name*/ On 1/30/20 7:42 PM, Leonid Vasiliev wrote: > In accordance with https://github.com/tarantool/tarantool/issues/4398 > a custom error type has been added to the box.error. > Now, it's possible to create an error with custom subtype (string value) > for use it in applications. > > Needed for #4398 > --- > src/box/errcode.h | 1 + > src/box/error.cc | 45 +++++++++++++++++++ > src/box/error.h | 24 ++++++++++ > src/box/lua/error.cc | 99 ++++++++++++++++++++++++++++++++---------- > src/lua/error.lua | 26 +++++++---- > test/box/misc.result | 19 ++++++++ > test/box/misc.test.lua | 9 ++++ > 7 files changed, 193 insertions(+), 30 deletions(-) > > diff --git a/src/box/errcode.h b/src/box/errcode.h > index 6f6e28c6c..ac4d69dda 100644 > --- a/src/box/errcode.h > +++ b/src/box/errcode.h > @@ -264,6 +264,7 @@ struct errcode_record { > /*209 */_(ER_SESSION_SETTING_INVALID_VALUE, "Session setting %s expected a value of type %s") \ > /*210 */_(ER_SQL_PREPARE, "Failed to prepare SQL statement: %s") \ > /*211 */_(ER_WRONG_QUERY_ID, "Prepared statement with id %u does not exist") \ > + /*212 */_(ER_CUSTOM_ERROR, "User custom error: %s") \ > > /* > * !IMPORTANT! Please follow instructions at start of the file > diff --git a/src/box/error.cc b/src/box/error.cc > index 47dce3305..2e01f33ee 100644 > --- a/src/box/error.cc > +++ b/src/box/error.cc > @@ -86,6 +86,16 @@ box_error_set(const char *file, unsigned line, uint32_t code, > return -1; > } > > +int > +box_custom_error_set(const char *file, unsigned line, > + const char *custom, const char *reason) > +{ > + struct error *e = BuildCustomError(file, line, custom); > + strcpy(e->errmsg, reason); > + diag_add_error(&fiber()->diag, e); > + return -1; > +} > + > /* }}} */ > > struct rmean *rmean_error = NULL; > @@ -253,3 +263,38 @@ BuildAccessDeniedError(const char *file, unsigned int line, > return e; > } > } > + > +static struct method_info customerror_methods[] = { > + make_method(&type_CustomError, "custom_type", &CustomError::custom_type), > + METHODS_SENTINEL > +}; > + > +const struct type_info type_CustomError = > + make_type("CustomError", &type_ClientError, > + customerror_methods); > + > +CustomError::CustomError(const char *file, unsigned int line, > + const char *custom_type) > + :ClientError(&type_CustomError, file, line, ER_CUSTOM_ERROR) > +{ > + error_format_msg(this, tnt_errcode_desc(m_errcode), > + custom_type ?: ""); > + > + if (custom_type) { > + strncpy(m_custom_type, custom_type, 63); > + m_custom_type[63] = '\0'; > + } else { > + m_custom_type[0] = '\0'; > + } > +} > + > +struct error * > +BuildCustomError(const char *file, unsigned int line, > + const char *custom_type) > +{ > + try { > + return new CustomError(file, line, custom_type); > + } catch (OutOfMemory *e) { > + return e; > + } > +} > diff --git a/src/box/error.h b/src/box/error.h > index b8c7cf73d..fcb5a2a43 100644 > --- a/src/box/error.h > +++ b/src/box/error.h > @@ -53,6 +53,9 @@ struct error * > BuildXlogGapError(const char *file, unsigned line, > const struct vclock *from, const struct vclock *to); > > +struct error * > +BuildCustomError(const char *file, unsigned int line, const char *custom_type); > + > /** \cond public */ > > struct error; > @@ -129,6 +132,10 @@ int > box_error_set(const char *file, unsigned line, uint32_t code, > const char *format, ...); > > +int > +box_custom_error_set(const char *file, unsigned line, > + const char *custom, const char *reason); > + > /** > * A backward-compatible API define. > */ > @@ -140,6 +147,7 @@ box_error_set(const char *file, unsigned line, uint32_t code, > extern const struct type_info type_ClientError; > extern const struct type_info type_XlogError; > extern const struct type_info type_AccessDeniedError; > +extern const struct type_info type_CustomError; > > #if defined(__cplusplus) > } /* extern "C" */ > @@ -266,6 +274,22 @@ struct XlogGapError: public XlogError > virtual void raise() { throw this; } > }; > > +class CustomError: public ClientError > +{ > +public: > + CustomError(const char *file, unsigned int line, > + const char *custom_type); > + > + const char* > + custom_type() > + { > + return m_custom_type ?: "(nil)"; > + } > +private: > + /** Custom type name*/ > + char m_custom_type[64]; > +}; > + > #endif /* defined(__cplusplus) */ > > #endif /* TARANTOOL_BOX_ERROR_H_INCLUDED */ > diff --git a/src/box/lua/error.cc b/src/box/lua/error.cc > index fc53a40f4..f69aaa5cb 100644 > --- a/src/box/lua/error.cc > +++ b/src/box/lua/error.cc > @@ -43,31 +43,35 @@ extern "C" { > #include "box/error.h" > > static void > -luaT_error_create(lua_State *L, int top_base) > -{ > - uint32_t code = 0; > - const char *reason = NULL; > - const char *file = ""; > - unsigned line = 0; > - lua_Debug info; > +luaT_error_read_args(lua_State *L, int top_base, uint32_t *code, > + const char **custom_type, const char **reason) { > int top = lua_gettop(L); > if (top >= top_base && lua_type(L, top_base) == LUA_TNUMBER) { > - code = lua_tonumber(L, top_base); > - reason = tnt_errcode_desc(code); > + *code = lua_tonumber(L, top_base); > + *reason = tnt_errcode_desc(*code); > if (top > top_base) { > + int shift = 1; > + if (*code == ER_CUSTOM_ERROR) { > + *custom_type = lua_tostring(L, top_base + 1); > + shift = 2; > + } > + > /* Call string.format(reason, ...) to format message */ > lua_getglobal(L, "string"); > if (lua_isnil(L, -1)) > - goto raise; > + return; > lua_getfield(L, -1, "format"); > if (lua_isnil(L, -1)) > - goto raise; > - lua_pushstring(L, reason); > - for (int i = top_base + 1; i <= top; i++) > + return; > + > + lua_pushstring(L, *reason); > + int nargs = 1; > + for (int i = top_base + shift; i <= top; ++i, ++nargs) > lua_pushvalue(L, i); > - lua_call(L, top - top_base + 1, 1); > - reason = lua_tostring(L, -1); > - } else if (strchr(reason, '%') != NULL) { > + > + lua_call(L, nargs, 1); > + *reason = lua_tostring(L, -1); > + } else if (strchr(*reason, '%') != NULL) { > /* Missing arguments to format string */ > luaL_error(L, "box.error(): bad arguments"); > } > @@ -75,12 +79,15 @@ luaT_error_create(lua_State *L, int top_base) > if (lua_istable(L, top_base)) { > /* A special case that rethrows raw error (used by net.box) */ > lua_getfield(L, top_base, "code"); > - code = lua_tonumber(L, -1); > + *code = lua_tonumber(L, -1); > lua_pop(L, 1); > + if (*code == ER_CUSTOM_ERROR) { > + lua_getfield(L, top_base, "custom_type"); > + *custom_type = lua_tostring(L, -1); > + lua_pop(L, 1); > + } > lua_getfield(L, top_base, "reason"); > - reason = lua_tostring(L, -1); > - if (reason == NULL) > - reason = ""; > + *reason = lua_tostring(L, -1); > lua_pop(L, 1); > } else if (luaL_iserror(L, top_base)) { > lua_error(L); > @@ -90,7 +97,21 @@ luaT_error_create(lua_State *L, int top_base) > luaL_error(L, "box.error(): bad arguments"); > } > > -raise: > + return; > +} > + > +static void > +luaT_error_create(lua_State *L, int top_base) > +{ > + uint32_t code = 0; > + const char *custom_type = NULL; > + const char *reason = NULL; > + > + luaT_error_read_args(L, top_base, &code, &custom_type, &reason); > + > + const char *file = ""; > + unsigned line = 0; > + lua_Debug info; > if (lua_getstack(L, 1, &info) && lua_getinfo(L, "Sl", &info)) { > if (*info.short_src) { > file = info.short_src; > @@ -101,8 +122,16 @@ raise: > } > line = info.currentline; > } > + > + if (reason == NULL) > + reason = ""; > say_debug("box.error() at %s:%i", file, line); > - box_error_set(file, line, code, "%s", reason); > + if (code == ER_CUSTOM_ERROR) { > + box_custom_error_set(file, line, > + custom_type ? custom_type : "", reason); > + } else { > + box_error_set(file, line, code, "%s", reason); > + } > } > > static int > @@ -144,6 +173,28 @@ luaT_error_new(lua_State *L) > return luaT_error_last(L); > } > > +static int > +luaT_error_custom_type(lua_State *L) > +{ > + struct error *e = luaL_checkerror(L, -1); > + > + if (e->type == NULL || e->type->name == NULL > + || strcmp(e->type->name, "CustomError")) { > + lua_pushfstring(L, "%s has't a custom type",e->type->name); > + return 1;; > + } > + > + const struct method_info *custom_type_m = > + type_method_by_name(e->type, "custom_type"); > + assert(custom_type_m != NULL); > + > + const char *custom_type = exception_get_string(e, custom_type_m); > + assert(custom_type != NULL); > + > + lua_pushstring(L, custom_type); > + return 1; > +} > + > static int > luaT_error_clear(lua_State *L) > { > @@ -268,6 +319,10 @@ box_lua_error_init(struct lua_State *L) { > lua_pushcfunction(L, luaT_error_new); > lua_setfield(L, -2, "new"); > } > + { > + lua_pushcfunction(L, luaT_error_custom_type); > + lua_setfield(L, -2, "custom_type"); > + } > lua_setfield(L, -2, "__index"); > } > lua_setmetatable(L, -2); > diff --git a/src/lua/error.lua b/src/lua/error.lua > index f296ecf94..6056718cc 100644 > --- a/src/lua/error.lua > +++ b/src/lua/error.lua > @@ -104,8 +104,13 @@ local function error_errno(err) > return e > end > > +local function error_custom_type(err) > + return box.error.custom_type(err) > +end > + > local error_fields = { > ["type"] = error_type, > + ["custom_type"] = error_custom_type, > ["message"] = error_message, > ["trace"] = error_trace, > ["errno"] = error_errno, > @@ -148,11 +153,16 @@ local function error_serialize(err) > return error_message(err) > end > > +local function error_is_custom(err) > + return ffi.string(err._type.name) == 'CustomError' > +end > + > local error_methods = { > - ["unpack"] = error_unpack; > - ["raise"] = error_raise; > - ["match"] = error_match; -- Tarantool 1.6 backward compatibility > - ["__serialize"] = error_serialize; > + ["unpack"] = error_unpack, > + ["raise"] = error_raise, > + ["match"] = error_match, -- Tarantool 1.6 backward compatibility > + ["is_custom"] = error_is_custom, > + ["__serialize"] = error_serialize > } > > local function error_index(err, key) > @@ -181,11 +191,11 @@ local function error_concat(lhs, rhs) > end > > local error_mt = { > - __index = error_index; > - __tostring = error_message; > - __concat = error_concat; > + __index = error_index, > + __tostring = error_message, > + __concat = error_concat > }; > > -ffi.metatype('struct error', error_mt); > +ffi.metatype('struct error', error_mt) > > return error > diff --git a/test/box/misc.result b/test/box/misc.result > index b94ba5058..96c12784c 100644 > --- a/test/box/misc.result > +++ b/test/box/misc.result > @@ -308,6 +308,24 @@ type(err.errno) > --- > - nil > ... > +-- > +-- gh-4398-expose-error-module > +-- > +err_custom = box.error.new(box.error.CUSTOM_ERROR, "My Custom Type", "Reason") > +--- > +... > +err_custom.type == "CustomError" > +--- > +- true > +... > +err_custom.custom_type == "My Custom Type" > +--- > +- true > +... > +err_custom.message == "User custom error: Reason" > +--- > +- true > +... > ---------------- > -- # box.stat > ---------------- > @@ -654,6 +672,7 @@ t; > 209: box.error.SESSION_SETTING_INVALID_VALUE > 210: box.error.SQL_PREPARE > 211: box.error.WRONG_QUERY_ID > + 212: box.error.CUSTOM_ERROR > ... > test_run:cmd("setopt delimiter ''"); > --- > diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua > index e82ac2cf9..92b3a12f3 100644 > --- a/test/box/misc.test.lua > +++ b/test/box/misc.test.lua > @@ -99,6 +99,15 @@ type(err.errno) > err = box.error.new(box.error.PROC_LUA, "errno") > type(err.errno) > > +-- > +-- gh-4398-expose-error-module > +-- > + > +err_custom = box.error.new(box.error.CUSTOM_ERROR, "My Custom Type", "Reason") > +err_custom.type == "CustomError" > +err_custom.custom_type == "My Custom Type" > +err_custom.message == "User custom error: Reason" > + > ---------------- > -- # box.stat > ---------------- >