[Tarantool-patches] [PATCH 2/2] Add the custom error type
Leonid Vasiliev
lvasiliev at tarantool.org
Fri Jan 31 10:43:45 MSK 2020
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
> ----------------
>
More information about the Tarantool-patches
mailing list