diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index 4653a3f2e4775062f6ba4efcf0951225726bc96a..8438499ae1e07ca6e6067f2f4b6085df93c979ff 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -891,6 +891,36 @@ lua box.dostring('local f = function(key) t=box.select(0, 0, key); if t ~= nil t </programlisting> </listitem> </varlistentry> + <varlistentry> + <term> + <emphasis role="lua">box.raise(errcode, errtext)</emphasis> + </term> + <listitem> + <para> + Raises a client error. The difference between this function + and the built-in <code>error()</code> function in Lua + is that when the error reaches the client, it's error code + is preserved, whereas every Lua error is presented to the + client as <constant>ER_PROC_LUA</constant>. This function + makes it possible to emulate any kind of native exception, + such as a unique constraint violation, no such space/index, + etc. A complete list of errors is present in <link xlink:href="https://github.com/mailru/tarantool/blob/master/include/errcode.h">errcode.h</link> + file in the source tree. + Lua constants which correspond to Tarantool/Box errors + are defined in <code>box.error</code> module. The error + message can be arbitrary. + Throws client error. Lua procedure can emulate any + request errors (for example: unique key exception). + </para> + <bridgehead renderas="sect4">Example</bridgehead> + <programlisting> + lua box.raise(box.error.ER_WAL_IO, 'Wal I/O error') + --- + error: 'Wal I/O error' + ... + </programlisting> + </listitem> + </varlistentry> <varlistentry> <term> <emphasis role="lua">box.auto_increment(space_no, ...)</emphasis> diff --git a/include/exception.h b/include/exception.h index f226f6b8709416586e059dcb3ce647be15469838..7f23523e543b21ef8955f4ccf7018b6d8e40616a 100644 --- a/include/exception.h +++ b/include/exception.h @@ -75,6 +75,7 @@ } - (id) init: (uint32_t)errcode_, ...; +- (id) init: (uint32_t)errcode_ :(const char *)msg; - (id) init: (uint32_t)errcode_ args :(va_list)ap; - (void) log; - (const char *) errmsg; diff --git a/src/box/box_lua.m b/src/box/box_lua.m index 9e9b45547dc8265d717916b14cc0d7f674329e8c..d0ae1e17f983d79fd035f9ec2445910afb1fe932 100644 --- a/src/box/box_lua.m +++ b/src/box/box_lua.m @@ -1147,8 +1147,22 @@ lbox_process(lua_State *L) return lua_gettop(L) - top; } +static int +lbox_raise(lua_State *L) +{ + if (lua_gettop(L) != 2) + luaL_error(L, "box.raise(): bad arguments"); + uint32_t code = lua_tointeger(L, 1); + if (!code) + luaL_error(L, "box.raise(): unknown error code"); + const char *str = lua_tostring(L, 2); + tnt_raise(ClientError, :code :str); + return 0; +} + static const struct luaL_reg boxlib[] = { {"process", lbox_process}, + {"raise", lbox_raise}, {NULL, NULL} }; diff --git a/src/exception.m b/src/exception.m index b65ff6e9467f80a0ff61a760c6c038561d876e6a..a09b6d39037a4938ca9404bf445534a80c2a1a06 100644 --- a/src/exception.m +++ b/src/exception.m @@ -113,6 +113,14 @@ return self; } +- (id) init: (uint32_t)errcode_ :(const char *)msg +{ + [super init]; + errcode = errcode_; + snprintf(errmsg, sizeof(errmsg), "%s", msg); + return self; +} + - (void) log { say_error("%s at %s:%d, %s", object_getClassName(self), diff --git a/test/box/lua.result b/test/box/lua.result index 77fab6ea919ef47c01d41d8690cad03b60e768f5..5a632589e0604caabec4db3bb329f3a884024274 100644 --- a/test/box/lua.result +++ b/test/box/lua.result @@ -16,32 +16,33 @@ lua for n in pairs(box) do print(' - box.', n) end - box.space - box.cfg - box.on_reload_configuration + - box.bless_space - box.time64 - box.uuid - box.ipc - box.delete - - box.bless_space - - box.replace - box.counter + - box.replace - box.auto_increment + - box.update - box.time - box.select_range - box.insert - - box.update - box.select_reverse_range + - box.select - box.info - box.session - box.uuid_hex - - box.select + - box.dostring - box.slab - box.process - - box.dostring - box.select_limit - - box.stat - box.flags + - box.stat + - box.index - box.unpack - box.pack - - box.index + - box.raise - box.socket ... lua box.pack() diff --git a/test/box/lua_misc.result b/test/box/lua_misc.result new file mode 100644 index 0000000000000000000000000000000000000000..769a15530bfd45868ced886e2109205ba23ce8d4 --- /dev/null +++ b/test/box/lua_misc.result @@ -0,0 +1,94 @@ + +# +# box.raise +# + +lua 1 + 1 +--- + - 2 +... +lua box.raise(123, 'test') +--- +error: 'test' +... +lua box.raise(0, 'the other test') +--- +error: 'box.raise(): unknown error code' +... +lua box.raise(12, 345) +--- +error: '345' +... + +# +# box.stat +# + +lua for k, v in pairs(box.stat()) do print(k) end +--- +DELETE +SELECT +REPLACE +CALL +UPDATE +DELETE_1_3 +... +lua for k, v in pairs(box.stat().DELETE) do print(k) end +--- +total +rps +... +lua for k, v in pairs(box.stat.DELETE) do print(k) end +--- +total +rps +... + +# +# box.space +# + +lua type(box) +--- + - table +... +lua type(box.space) +--- + - table +... +lua box.cfg.memcached_space +--- + - 23 +... +lua for i, v in pairs(box.space[0].index[0].key_field[0]) do print(i, ': ', v) end +--- +type: NUM +fieldno: 0 +... + +# +# box.space +# + +lua string.match(tostring(box.slab), '^table:') ~= nil +--- + - true +... +lua box.slab.arena_used >= 0 +--- + - true +... +lua box.slab.arena_size > 0 +--- + - true +... +lua string.match(tostring(box.slab.slabs), '^table:') ~= nil +--- + - true +... +lua for k, v in pairs(box.slab()) do print(k) end +--- +slabs +arena_size +arena_used +... diff --git a/test/box/lua_misc.test b/test/box/lua_misc.test new file mode 100644 index 0000000000000000000000000000000000000000..1aff48928406df26ba827975bb379fd114ce9ab4 --- /dev/null +++ b/test/box/lua_misc.test @@ -0,0 +1,43 @@ +# encoding: tarantool +print """ +# +# box.raise +# +""" +exec admin "lua 1 + 1" +exec admin "lua box.raise(123, 'test')" +exec admin "lua box.raise(0, 'the other test')" +exec admin "lua box.raise(12, 345)" + +print """ +# +# box.stat +# +""" + +exec admin "lua for k, v in pairs(box.stat()) do print(k) end" +exec admin "lua for k, v in pairs(box.stat().DELETE) do print(k) end" +exec admin "lua for k, v in pairs(box.stat.DELETE) do print(k) end" + +print """ +# +# box.space +# +""" + +exec admin "lua type(box)" +exec admin "lua type(box.space)" +exec admin "lua box.cfg.memcached_space" +exec admin "lua for i, v in pairs(box.space[0].index[0].key_field[0]) do print(i, ': ', v) end" + +print """ +# +# box.space +# +""" + +exec admin "lua string.match(tostring(box.slab), '^table:') ~= nil" +exec admin "lua box.slab.arena_used >= 0" +exec admin "lua box.slab.arena_size > 0" +exec admin "lua string.match(tostring(box.slab.slabs), '^table:') ~= nil" +exec admin "lua for k, v in pairs(box.slab()) do print(k) end" diff --git a/test/box/slab.result b/test/box/slab.result deleted file mode 100644 index 07a80527be565c3bba6a7f64d601674db3c02fb7..0000000000000000000000000000000000000000 --- a/test/box/slab.result +++ /dev/null @@ -1,22 +0,0 @@ -lua string.match(tostring(box.slab), '^table:') ~= nil ---- - - true -... -lua box.slab.arena_used >= 0 ---- - - true -... -lua box.slab.arena_size > 0 ---- - - true -... -lua string.match(tostring(box.slab.slabs), '^table:') ~= nil ---- - - true -... -lua for k, v in pairs(box.slab()) do print(k) end ---- -slabs -arena_size -arena_used -... diff --git a/test/box/slab.test b/test/box/slab.test deleted file mode 100644 index 9adf3dcd7577c42a43429e63c22f7a2cc7118e5e..0000000000000000000000000000000000000000 --- a/test/box/slab.test +++ /dev/null @@ -1,9 +0,0 @@ -# encoding: tarantool -# -import sys - -exec admin "lua string.match(tostring(box.slab), '^table:') ~= nil" -exec admin "lua box.slab.arena_used >= 0" -exec admin "lua box.slab.arena_size > 0" -exec admin "lua string.match(tostring(box.slab.slabs), '^table:') ~= nil" -exec admin "lua for k, v in pairs(box.slab()) do print(k) end" diff --git a/test/box/space.result b/test/box/space.result deleted file mode 100644 index 4d48f37e129d6f7a4a64187a4f186a7952535470..0000000000000000000000000000000000000000 --- a/test/box/space.result +++ /dev/null @@ -1,17 +0,0 @@ -lua type(box) ---- - - table -... -lua type(box.space) ---- - - table -... -lua box.cfg.memcached_space ---- - - 23 -... -lua for i, v in pairs(box.space[0].index[0].key_field[0]) do print(i, ': ', v) end ---- -type: NUM -fieldno: 0 -... diff --git a/test/box/space.test b/test/box/space.test deleted file mode 100644 index a421d2685268a19bfd5d8c34231f3bd7a7512afb..0000000000000000000000000000000000000000 --- a/test/box/space.test +++ /dev/null @@ -1,5 +0,0 @@ -# encoding: tarantool -exec admin "lua type(box)" -exec admin "lua type(box.space)" -exec admin "lua box.cfg.memcached_space" -exec admin "lua for i, v in pairs(box.space[0].index[0].key_field[0]) do print(i, ': ', v) end" diff --git a/test/box/stat_lua.result b/test/box/stat_lua.result deleted file mode 100644 index 0d400c3ef1a0a7401deef8bd5b3cca3a8764c3df..0000000000000000000000000000000000000000 --- a/test/box/stat_lua.result +++ /dev/null @@ -1,19 +0,0 @@ -lua for k, v in pairs(box.stat()) do print(k) end ---- -DELETE -SELECT -REPLACE -CALL -UPDATE -DELETE_1_3 -... -lua for k, v in pairs(box.stat().DELETE) do print(k) end ---- -total -rps -... -lua for k, v in pairs(box.stat.DELETE) do print(k) end ---- -total -rps -... diff --git a/test/box/stat_lua.test b/test/box/stat_lua.test deleted file mode 100644 index 39c73e0d4f2a479e2d0b6672f2aec25d7b131c1a..0000000000000000000000000000000000000000 --- a/test/box/stat_lua.test +++ /dev/null @@ -1,7 +0,0 @@ -# encoding: tarantool -import os -import sys - -exec admin "lua for k, v in pairs(box.stat()) do print(k) end" -exec admin "lua for k, v in pairs(box.stat().DELETE) do print(k) end" -exec admin "lua for k, v in pairs(box.stat.DELETE) do print(k) end"