Tarantool development patches archive
 help / color / mirror / Atom feed
* [tarantool-patches] [PATCH v2 0/2] sql: rework error handling in box.execute()
@ 2019-07-31 10:32 imeevma
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error() imeevma
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: imeevma @ 2019-07-31 10:32 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: kostja, tarantool-patches

This patch-set reworks the error handling of box.execute(). After
this patch-set, box.execute() will return nil as the first return
value, and error as the second.

https://github.com/tarantool/tarantool/issues/4390
https://github.com/tarantool/tarantool/tree/imeevma/gh-4390-box_execute-should-not-throw

Changes in v2:
 - Added function, that pushes nil and error in Lua stack.

Mergen Imeev (2):
  lua: new function luaT_return_error()
  sql: rework error handling in box.execute()

 src/box/lua/execute.c                              |   4 +-
 src/box/lua/session.c                              |  12 +-
 src/lua/error.c                                    |  10 ++
 src/lua/error.h                                    |   9 +
 src/lua/fio.c                                      |  74 +++------
 src/lua/swim.c                                     |   7 +-
 test/sql-tap/gh2548-select-compound-limit.test.lua |  10 +-
 test/sql-tap/lua/sqltester.lua                     |   5 +-
 test/sql/bind.result                               |  14 +-
 test/sql/bind.test.lua                             |   8 +-
 test/sql/checks.result                             |  52 ++++--
 test/sql/clear.result                              |   9 +-
 test/sql/collation.result                          |  63 ++++---
 test/sql/delete.result                             |  19 ++-
 test/sql/drop-table.result                         |  16 +-
 test/sql/errinj.result                             |  54 ++++--
 test/sql/foreign-keys.result                       |  27 +--
 test/sql/gh-2929-primary-key.result                |  15 +-
 test/sql/gh-2981-check-autoinc.result              |  12 +-
 test/sql/gh-3613-idx-alter-update.result           |   3 +-
 test/sql/gh-3888-values-blob-assert.result         |  18 +-
 test/sql/icu-upper-lower.result                    |   9 +-
 test/sql/insert-unique.result                      |   6 +-
 test/sql/integer-overflow.result                   |  28 ++--
 test/sql/message-func-indexes.result               |  12 +-
 test/sql/misc.result                               |  31 ++--
 test/sql/no-pk-space.result                        |  15 +-
 test/sql/on-conflict.result                        |  38 +++--
 test/sql/persistency.result                        |  12 +-
 test/sql/row-count.result                          |   3 +-
 test/sql/savepoints.result                         |  16 +-
 test/sql/savepoints.test.lua                       |   5 +-
 test/sql/transition.result                         |  10 +-
 test/sql/transitive-transactions.result            |  14 +-
 test/sql/transitive-transactions.test.lua          |  10 +-
 test/sql/triggers.result                           |  19 ++-
 test/sql/types.result                              | 183 ++++++++++++++-------
 test/sql/view.result                               |  25 ++-
 38 files changed, 547 insertions(+), 330 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 10:32 [tarantool-patches] [PATCH v2 0/2] sql: rework error handling in box.execute() imeevma
@ 2019-07-31 10:32 ` imeevma
  2019-07-31 15:23   ` [tarantool-patches] " Alexander Turenko
  2019-07-31 17:15   ` Vladislav Shpilevoy
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 2/2] sql: rework error handling in box.execute() imeevma
  2019-08-02  5:39 ` [tarantool-patches] Re: [PATCH v2 0/2] " Kirill Yukhin
  2 siblings, 2 replies; 17+ messages in thread
From: imeevma @ 2019-07-31 10:32 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: kostja, tarantool-patches

Currently, if we have to return errors using the format
'return nil, error', we must do it manually. Since this error
return method is described in our Lua coding style, it makes sense
to create a function that will return an error in this format.
This patch creates a function.

Needed for #4390
---
 src/box/lua/session.c | 12 +++------
 src/lua/error.c       | 10 +++++++
 src/lua/error.h       |  9 +++++++
 src/lua/fio.c         | 74 +++++++++++++--------------------------------------
 src/lua/swim.c        |  7 +++--
 5 files changed, 45 insertions(+), 67 deletions(-)

diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index c0ac491..b6b2c07 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -395,14 +395,10 @@ lbox_session_push(struct lua_State *L)
 	}
 	struct port port;
 	port_lua_create(&port, L);
-	if (session_push(session, sync, &port) != 0) {
-		lua_pushnil(L);
-		luaT_pusherror(L, box_error_last());
-		return 2;
-	} else {
-		lua_pushboolean(L, true);
-		return 1;
-	}
+	if (session_push(session, sync, &port) != 0)
+		return luaT_return_error(L);
+	lua_pushboolean(L, true);
+	return 1;
 }
 
 /**
diff --git a/src/lua/error.c b/src/lua/error.c
index fca87f9..8cb7ca0 100644
--- a/src/lua/error.c
+++ b/src/lua/error.c
@@ -104,6 +104,16 @@ luaT_error(lua_State *L)
 	return 0;
 }
 
+int
+luaT_return_error(lua_State *L)
+{
+	struct error *e = diag_last_error(&fiber()->diag);
+	assert(e != NULL);
+	lua_pushnil(L);
+	luaT_pusherror(L, e);
+	return 2;
+}
+
 void
 tarantool_lua_error_init(struct lua_State *L)
 {
diff --git a/src/lua/error.h b/src/lua/error.h
index 67a43da..2d622d3 100644
--- a/src/lua/error.h
+++ b/src/lua/error.h
@@ -49,6 +49,15 @@ struct error;
 LUA_API int
 luaT_error(lua_State *L);
 
+/**
+ * Return nil as the first return value and an error as the
+ * second. The error is received using box_error_last().
+ *
+ * @param L Lua stack.
+ */
+LUA_API int
+luaT_return_error(lua_State *L);
+
 void
 luaT_pusherror(struct lua_State *L, struct error *e);
 /** \endcond public */
diff --git a/src/lua/fio.c b/src/lua/fio.c
index 55fa667..cb7e31e 100644
--- a/src/lua/fio.c
+++ b/src/lua/fio.c
@@ -47,11 +47,9 @@
 #include "lua/utils.h"
 #include "coio_file.h"
 
-static inline void
-lbox_fio_pushsyserror(struct lua_State *L)
-{
-	diag_set(SystemError, "fio: %s", strerror(errno));
-	luaT_pusherror(L, diag_get()->last);
+#define lbox_fio_pushsyserror(L) {				\
+	diag_set(SystemError, "fio: %s", strerror(errno));	\
+	return luaT_return_error(L);				\
 }
 
 static int
@@ -69,11 +67,8 @@ usage:
 	int mode = lua_tointeger(L, 3);
 
 	int fh = coio_file_open(pathname, flags, mode);
-	if (fh < 0) {
-		lua_pushnil(L);
+	if (fh < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushinteger(L, fh);
 	return 1;
 }
@@ -90,11 +85,8 @@ lbox_fio_pwrite(struct lua_State *L)
 	size_t offset = lua_tonumber(L, 4);
 
 	int res = coio_pwrite(fh, buf, len, offset);
-	if (res < 0) {
-		lua_pushnil(L);
+	if (res < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -115,11 +107,8 @@ lbox_fio_pread(struct lua_State *L)
 
 	int res = coio_pread(fh, buf, len, offset);
 
-	if (res < 0) {
-		lua_pushnil(L);
+	if (res < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -129,7 +118,10 @@ lbox_fio_pushbool(struct lua_State *L, bool res)
 {
 	lua_pushboolean(L, res);
 	if (!res) {
-		lbox_fio_pushsyserror(L);
+		diag_set(SystemError, "fio: %s", strerror(errno));
+		struct error *e = diag_last_error(diag_get());
+		assert(e != NULL);
+		luaT_pusherror(L, e);
 		return 2;
 	}
 	return 1;
@@ -211,11 +203,8 @@ lbox_fio_write(struct lua_State *L)
 	size_t len = lua_tonumber(L, 3);
 
 	int res = coio_write(fh, buf, len);
-	if (res < 0) {
-		lua_pushnil(L);
+	if (res < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -298,11 +287,8 @@ lbox_fio_read(struct lua_State *L)
 
 	int res = coio_read(fh, buf, len);
 
-	if (res < 0) {
-		lua_pushnil(L);
+	if (res < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -371,11 +357,8 @@ DEF_STAT_METHOD(is_sock, S_ISSOCK);
 static int
 lbox_fio_pushstat(struct lua_State *L, int res, const struct stat *stat)
 {
-	if (res < 0) {
-		lua_pushnil(L);
+	if (res < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_newtable(L);
 
 	PUSHTABLE("dev", lua_pushinteger, stat->st_dev);
@@ -518,11 +501,8 @@ lbox_fio_listdir(struct lua_State *L)
 	}
 	pathname = lua_tostring(L, 1);
 	char *buf;
-	if (coio_readdir(pathname, &buf) < 0) {
-		lua_pushnil(L);
+	if (coio_readdir(pathname, &buf) < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushstring(L, buf);
 	free(buf);
 	return 1;
@@ -613,11 +593,8 @@ usage:
 		goto usage;
 	char *path = (char *)lua_newuserdata(L, PATH_MAX);
 	int res = coio_readlink(pathname, path, PATH_MAX);
-	if (res < 0) {
-		lua_pushnil(L);
+	if (res < 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushlstring(L, path, res);
 	lua_remove(L, -2);
 	return 1;
@@ -629,16 +606,11 @@ lbox_fio_tempdir(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
 		lbox_fio_pushsyserror(L);
-		return 2;
 	}
 
-	if (coio_tempdir(buf, PATH_MAX) != 0) {
-		lua_pushnil(L);
+	if (coio_tempdir(buf, PATH_MAX) != 0)
 		lbox_fio_pushsyserror(L);
-		return 2;
-	}
 	lua_pushstring(L, buf);
 	lua_remove(L, -2);
 	return 1;
@@ -650,20 +622,12 @@ lbox_fio_cwd(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
 		lbox_fio_pushsyserror(L);
-		return 2;
 	}
-
-
-	if (getcwd(buf, PATH_MAX)) {
-		lua_pushstring(L, buf);
-		lua_remove(L, -2);
-	} else {
+	if (getcwd(buf, PATH_MAX) == NULL)
 		lbox_fio_pushsyserror(L);
-		lua_pushnil(L);
-		return 2;
-	}
+	lua_pushstring(L, buf);
+	lua_remove(L, -2);
 	return 1;
 }
 
diff --git a/src/lua/swim.c b/src/lua/swim.c
index 26646f4..6c35f9f 100644
--- a/src/lua/swim.c
+++ b/src/lua/swim.c
@@ -69,11 +69,10 @@ lua_swim_new(struct lua_State *L)
 {
 	uint64_t generation = luaL_checkuint64(L, 1);
 	struct swim *s = swim_new(generation);
+	if (s == NULL)
+		return luaT_return_error(L);
 	*(struct swim **) luaL_pushcdata(L, ctid_swim_ptr) = s;
-	if (s != NULL)
-		return 1;
-	luaT_pusherror(L, diag_last_error(diag_get()));
-	return 2;
+	return 1;
 }
 
 /**
-- 
2.7.4

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] [PATCH v2 2/2] sql: rework error handling in box.execute()
  2019-07-31 10:32 [tarantool-patches] [PATCH v2 0/2] sql: rework error handling in box.execute() imeevma
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error() imeevma
@ 2019-07-31 10:32 ` imeevma
  2019-07-31 22:23   ` [tarantool-patches] " Mergen Imeev
  2019-08-02  5:39 ` [tarantool-patches] Re: [PATCH v2 0/2] " Kirill Yukhin
  2 siblings, 1 reply; 17+ messages in thread
From: imeevma @ 2019-07-31 10:32 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: kostja, tarantool-patches

Hi! Thank you for review! My answers and new patch below. Also,
new patch appeared before this one that adds new function
luaT_return_error().

On 7/30/19 11:45 PM, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patch!
>
> On 30/07/2019 16:04, imeevma@tarantool.org wrote:
>> In accordance with the Lua coding style in Tarantool, all errors
>> returned in Lua should be returned using 'return nil, error'.
>> However, box.execute() throws an exception in case of an error.
>> This patch causes box.execute() to return an error, as described
>> in the coding style.
>>
>> Closes #4390
>> ---
>> https://github.com/tarantool/tarantool/issues/4390
>> https://github.com/tarantool/tarantool/tree/imeevma/gh-4390-box_execute-should-not-throw
>>
>> diff --git a/src/box/lua/execute.c b/src/box/lua/execute.c
>> index 7b7c575..85c5738 100644
>> --- a/src/box/lua/execute.c
>> +++ b/src/box/lua/execute.c
>> @@ -254,13 +254,25 @@ lbox_execute(struct lua_State *L)
>>  		if (! lua_istable(L, 2))
>>  			return luaL_error(L, "Second argument must be a table");
>>  		bind_count = lua_sql_bind_list_decode(L, &bind, 2);
>> -		if (bind_count < 0)
>> -			return luaT_error(L);
>> +		if (bind_count < 0) {
>> +			lua_pushnil(L);
>> +			struct error *e = box_error_last();
>> +			if (e == NULL)
>> +				return 1;
>> +			luaT_pusherror(L, e);
>
> First, how is it possible, that e == NULL? It should not be
> so. I deleted that check, and the tests passed. So please,
> drop it.
>
Fixed.

> Secondly, there are already 4 places, which push exactly the same
> nil + diag error. And 13 more intricate places in lua/fio.c.
> I propose you to introduce a new function to push nil + last box
> error.
>
> Another place is lua_swim_new, which pushes nil implicitly,
> when in the expression:
>
>     *(struct swim **) luaL_pushcdata(L, ctid_swim_ptr) = s;
>
> 's' is NULL. But in fact it is the same case, and here you can
> use than new function too.
>
> Please, introduce and use that new function in a separate commit
> before this one.
Done.


New patch:

From 03d49126761e232a9ac08719680e08ff21489665 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Tue, 30 Jul 2019 15:50:29 +0300
Subject: [PATCH] sql: rework error handling in box.execute()

In accordance with the Lua coding style in Tarantool, all errors
returned in Lua should be returned using 'return nil, error'.
However, box.execute() throws an exception in case of an error.
This patch causes box.execute() to return an error, as described
in the coding style.

Closes #4390

diff --git a/src/box/lua/execute.c b/src/box/lua/execute.c
index 7b7c575..9b1fc38 100644
--- a/src/box/lua/execute.c
+++ b/src/box/lua/execute.c
@@ -255,12 +255,12 @@ lbox_execute(struct lua_State *L)
 			return luaL_error(L, "Second argument must be a table");
 		bind_count = lua_sql_bind_list_decode(L, &bind, 2);
 		if (bind_count < 0)
-			return luaT_error(L);
+			return luaT_return_error(L);
 	}
 
 	if (sql_prepare_and_execute(sql, length, bind, bind_count, &port,
 				    &fiber()->gc) != 0)
-		return luaT_error(L);
+		return luaT_return_error(L);
 	port_dump_lua(&port, L, false);
 	port_destroy(&port);
 	return 1;
diff --git a/test/sql-tap/gh2548-select-compound-limit.test.lua b/test/sql-tap/gh2548-select-compound-limit.test.lua
index 9589a37..f578870 100755
--- a/test/sql-tap/gh2548-select-compound-limit.test.lua
+++ b/test/sql-tap/gh2548-select-compound-limit.test.lua
@@ -14,30 +14,30 @@ for _, term in ipairs({'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT'}) do
                  function()
                      for i = 1,table_count do
                          drop_string = 'DROP TABLE IF EXISTS t' .. i .. ';\n'
-                         box.execute(drop_string)
+                         test:execsql(drop_string)
                      end
 
                      for i = 1,table_count do
                          create_string = 'CREATE TABLE t' .. i .. ' (s1 int primary key, s2 int);\n'
-                         box.execute(create_string)
+                         test:execsql(create_string)
                      end
 
                      for i = 1,table_count do
                          insert_string = 'INSERT INTO t' .. i .. ' VALUES (0,' .. i .. ');\n'
-                         box.execute(insert_string)
+                         test:execsql(insert_string)
                      end
 
                      for i = 1,table_count-1 do
                          if i > 1 then select_string = select_string .. ' ' .. term .. ' ' end
                          select_string = select_string .. 'SELECT * FROM t' .. i
                      end
-                     return pcall( function() box.execute(select_string) end)
+                     return pcall( function() test:execsql(select_string) end)
                  end,
                  true)
     test:do_test("Negative COMPOUND "..term,
                  function()
                      select_string = select_string .. ' ' .. term ..' ' .. 'SELECT * FROM t' .. table_count
-                     return  pcall(function() box.execute(select_string) end)
+                     return  pcall(function() test:execsql(select_string) end)
                  end,
                  false)
 
diff --git a/test/sql-tap/lua/sqltester.lua b/test/sql-tap/lua/sqltester.lua
index e83a8e4..0f34114 100644
--- a/test/sql-tap/lua/sqltester.lua
+++ b/test/sql-tap/lua/sqltester.lua
@@ -150,7 +150,10 @@ local function execsql_one_by_one(sql)
     local last_res_rows = nil
     local last_res_metadata = nil
     for _, query in pairs(queries) do
-        local new_res = box.execute(query)
+        local new_res, err = box.execute(query)
+        if err ~= nil then
+            error(err)
+        end
         if new_res ~= nil and new_res.rows ~= nil then
             last_res_rows = new_res.rows
             last_res_metadata = new_res.metadata
diff --git a/test/sql/bind.result b/test/sql/bind.result
index cd0fcc0..1e02620 100644
--- a/test/sql/bind.result
+++ b/test/sql/bind.result
@@ -36,7 +36,13 @@ if remote then
 	cn = netbox.connect(box.cfg.listen)
 	execute = function(...) return cn:execute(...) end
 else
-	execute = box.execute
+	execute = function(...)
+		local res, err = box.execute(...)
+		if err ~= nil then
+			error(err)
+		end
+		return res
+	end
 end;
 ---
 ...
@@ -310,9 +316,11 @@ box.execute('DROP TABLE test')
 ...
 box.execute('SELECT ?', {1, 2})
 ---
-- error: 'Failed to execute SQL statement: The number of parameters is too large'
+- null
+- 'Failed to execute SQL statement: The number of parameters is too large'
 ...
 box.execute('SELECT $2', {1, 2, 3})
 ---
-- error: 'Failed to execute SQL statement: The number of parameters is too large'
+- null
+- 'Failed to execute SQL statement: The number of parameters is too large'
 ...
diff --git a/test/sql/bind.test.lua b/test/sql/bind.test.lua
index f311a0a..2b41af7 100644
--- a/test/sql/bind.test.lua
+++ b/test/sql/bind.test.lua
@@ -15,7 +15,13 @@ if remote then
 	cn = netbox.connect(box.cfg.listen)
 	execute = function(...) return cn:execute(...) end
 else
-	execute = box.execute
+	execute = function(...)
+		local res, err = box.execute(...)
+		if err ~= nil then
+			error(err)
+		end
+		return res
+	end
 end;
 test_run:cmd("setopt delimiter ''");
 --
diff --git a/test/sql/checks.result b/test/sql/checks.result
index b205149..f919862 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -73,7 +73,8 @@ box.space._ck_constraint:count({})
 ...
 box.execute("INSERT INTO \"test\" VALUES(5);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
 ...
 box.space.test:insert({5})
 ---
@@ -89,7 +90,8 @@ box.execute("INSERT INTO \"test\" VALUES(5);")
 ...
 box.execute("INSERT INTO \"test\" VALUES(6);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
 ...
 box.space.test:insert({6})
 ---
@@ -126,7 +128,8 @@ box.space._ck_constraint:count()
 ...
 box.execute("INSERT INTO t1 VALUES (7, 1, 1)")
 ---
-- error: 'Check constraint failed ''ONE'': x<5'
+- null
+- 'Check constraint failed ''ONE'': x<5'
 ...
 box.space.T1:insert({7, 1, 1})
 ---
@@ -134,7 +137,8 @@ box.space.T1:insert({7, 1, 1})
 ...
 box.execute("INSERT INTO t1 VALUES (2, 1, 1)")
 ---
-- error: 'Check constraint failed ''TWO'': y>x'
+- null
+- 'Check constraint failed ''TWO'': y>x'
 ...
 box.space.T1:insert({2, 1, 1})
 ---
@@ -155,7 +159,8 @@ box.execute("DROP TABLE t1")
 -- Test space creation rollback on spell error in ck constraint.
 box.execute("CREATE TABLE first (id NUMBER PRIMARY KEY CHECK(id < 5), a INT CONSTRAINT ONE CHECK(a >< 5));")
 ---
-- error: Syntax error near '<'
+- null
+- Syntax error near '<'
 ...
 box.space.FIRST == nil
 ---
@@ -184,14 +189,16 @@ _ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y'})
 ...
 box.execute("INSERT INTO \"test\" VALUES(2, 1);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 s:format({{name='Y', type='integer'}, {name='X', type='integer'}})
 ---
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(2, 1);")
 ---
@@ -202,7 +209,8 @@ s:truncate()
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 s:format({})
 ---
@@ -234,11 +242,13 @@ _ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'})
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''conflict'': X>10'
+- null
+- 'Check constraint failed ''conflict'': X>10'
 ...
 box.execute("INSERT INTO \"test\" VALUES(11, 11);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(12, 11);")
 ---
@@ -249,7 +259,8 @@ s:drop()
 ...
 box.execute("CREATE TABLE T2(ID INT PRIMARY KEY, CONSTRAINT CK1 CHECK(ID > 0), CONSTRAINT CK1 CHECK(ID < 0))")
 ---
-- error: Constraint CK1 already exists
+- null
+- Constraint CK1 already exists
 ...
 box.space.T2
 ---
@@ -264,20 +275,23 @@ box.space._ck_constraint:select()
 --
 box.execute("CREATE TABLE w2 (s1 INT PRIMARY KEY, CHECK ((SELECT COUNT(*) FROM w2) = 0));")
 ---
-- error: 'Failed to create check constraint ''CK_CONSTRAINT_1_W2'': Subqueries are
-    prohibited in a ck constraint definition'
+- null
+- 'Failed to create check constraint ''CK_CONSTRAINT_1_W2'': Subqueries are prohibited
+  in a ck constraint definition'
 ...
 box.execute("DROP TABLE w2;")
 ---
-- error: Space 'W2' does not exist
+- null
+- Space 'W2' does not exist
 ...
 --
 -- gh-3653: Dissallow bindings for DDL
 --
 box.execute("CREATE TABLE t5(x INT PRIMARY KEY, y INT, CHECK( x*y < ? ));")
 ---
-- error: 'Failed to create check constraint ''CK_CONSTRAINT_1_T5'': bindings are not
-    allowed in DDL'
+- null
+- 'Failed to create check constraint ''CK_CONSTRAINT_1_T5'': bindings are not allowed
+  in DDL'
 ...
 -- Test trim CK constraint code correctness.
 box.execute("CREATE TABLE t1(x TEXT PRIMARY KEY CHECK(x    LIKE     '1  a'))")
@@ -290,11 +304,13 @@ box.space._ck_constraint:select()[1].code
 ...
 box.execute("INSERT INTO t1 VALUES('1 a')")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
 ...
 box.execute("INSERT INTO t1 VALUES('1   a')")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
 ...
 box.execute("INSERT INTO t1 VALUES('1  a')")
 ---
diff --git a/test/sql/clear.result b/test/sql/clear.result
index 2fb1761..afa6520 100644
--- a/test/sql/clear.result
+++ b/test/sql/clear.result
@@ -176,7 +176,8 @@ box.execute("DROP TABLE zoobar")
 --
 box.execute("CREATE TABLE t1(id INT PRIMARY KEY, CONSTRAINT ck1 CHECK(id > 0), CONSTRAINT ck1 CHECK(id < 0));")
 ---
-- error: Constraint CK1 already exists
+- null
+- Constraint CK1 already exists
 ...
 box.space.t1
 ---
@@ -188,7 +189,8 @@ box.space._ck_constraint:select()
 ...
 box.execute("CREATE TABLE t2(id INT PRIMARY KEY, CONSTRAINT fk1 FOREIGN KEY(id) REFERENCES t2, CONSTRAINT fk1 FOREIGN KEY(id) REFERENCES t2);")
 ---
-- error: Constraint FK1 already exists
+- null
+- Constraint FK1 already exists
 ...
 box.space.t2
 ---
@@ -204,7 +206,8 @@ box.space._fk_constraint:select()
 --
 box.execute("CREATE TABLE t3(id INT PRIMARY KEY, CONSTRAINT ck1 CHECK(id > 0), CONSTRAINT ck1 FOREIGN KEY(id) REFERENCES t3, CONSTRAINT fk1 FOREIGN KEY(id) REFERENCES t3, CONSTRAINT ck1 CHECK(id < 0));")
 ---
-- error: Constraint CK1 already exists
+- null
+- Constraint CK1 already exists
 ...
 box.space.t1
 ---
diff --git a/test/sql/collation.result b/test/sql/collation.result
index 436ce32..11962ef 100644
--- a/test/sql/collation.result
+++ b/test/sql/collation.result
@@ -15,23 +15,28 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 -- All of these tests should throw error "near "COLLATE": syntax error"
 box.execute("SELECT 1 LIMIT 1 COLLATE BINARY;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1 COLLATE BINARY OFFSET 1;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1 OFFSET 1 COLLATE BINARY;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1, 1 COLLATE BINARY;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1 COLLATE BINARY, 1;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 -- gh-3052: upper/lower support only default locale
 -- For tr-TR result depends on collation
@@ -253,7 +258,8 @@ box.execute("SELECT * FROM t WHERE a COLLATE \"binary\" = b;")
 ...
 box.execute("SELECT * FROM t WHERE b = c;")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT * FROM t WHERE b COLLATE \"binary\" = c;")
 ---
@@ -283,22 +289,26 @@ box.execute("SELECT * FROM t WHERE a = c;")
 ...
 box.execute("SELECT * FROM t WHERE a COLLATE \"binary\" = c COLLATE \"unicode\";")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 -- Compound queries perform implicit comparisons between values.
 -- Hence, rules for collations compatibilities are the same.
 --
 box.execute("SELECT 'abc' COLLATE \"binary\" UNION SELECT 'ABC' COLLATE \"unicode_ci\"")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT 'abc' COLLATE \"unicode_ci\" UNION SELECT 'ABC' COLLATE binary")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT c FROM t UNION SELECT b FROM t;")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT b FROM t UNION SELECT a FROM t;")
 ---
@@ -345,7 +355,8 @@ box.session.su('tmp')
 -- Error: read access to space is denied.
 box.execute("pragma collation_list")
 ---
-- error: Read access to space '_collation' is denied for user 'tmp'
+- null
+- Read access to space '_collation' is denied for user 'tmp'
 ...
 box.session.su('admin')
 ---
@@ -426,7 +437,8 @@ box.execute("INSERT INTO t1 VALUES (1,'a');")
 -- Should fail.
 box.execute("UPDATE t0 SET s1 = 'A';")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.execute("SELECT * FROM t1;")
 ---
@@ -496,11 +508,13 @@ box.execute("SELECT c FROM t4a WHERE (a COLLATE \"binary\"||'') = b;")
 --
 box.execute("SELECT c FROM t4a WHERE (a COLLATE \"binary\"||'' COLLATE \"unicode_ci\") = b;")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT c FROM t4a WHERE (a COLLATE \"binary\"||'') = b COLLATE \"unicode\";")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 -- No collation is used since LHS and RHS of concatenation
 -- operator have different implicit collations.
@@ -555,7 +569,8 @@ box.execute("SELECT c FROM t4a WHERE (a||b COLLATE \"binary\")=(b||a);")
 ...
 box.execute("SELECT c FROM t4a WHERE (a||b COLLATE \"binary\")=(b COLLATE \"unicode_ci\"||a);")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("INSERT INTO t4b VALUES('abc', 'xxx', 2);")
 ---
@@ -676,7 +691,8 @@ box.execute("INSERT INTO t3b VALUES ('A');")
 ...
 box.execute("INSERT INTO t3b VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3B_1' in space 'T3B'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3B_1' in space 'T3B'
 ...
 box.execute("SELECT * FROM t3b;")
 ---
@@ -740,7 +756,8 @@ box.execute("INSERT INTO t3c VALUES ('A');")
 ...
 box.execute("INSERT INTO t3c VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3C_1' in space 'T3C'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3C_1' in space 'T3C'
 ...
 box.execute("SELECT * FROM t3c;")
 ---
@@ -804,7 +821,8 @@ box.execute("INSERT INTO t3d VALUES ('A');")
 ...
 box.execute("INSERT INTO t3d VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3D_1' in space 'T3D'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3D_1' in space 'T3D'
 ...
 box.execute("SELECT * FROM t3d;")
 ---
@@ -834,7 +852,8 @@ box.execute("INSERT INTO t3e VALUES ('a');")
 ...
 box.execute("INSERT INTO t3e VALUES ('A');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3E_1' in space 'T3E'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3E_1' in space 'T3E'
 ...
 box.execute("SELECT * FROM t3e;")
 ---
@@ -897,7 +916,8 @@ box.execute("INSERT INTO t3f VALUES ('A');")
 ...
 box.execute("INSERT INTO t3f VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3F_1' in space 'T3F'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3F_1' in space 'T3F'
 ...
 box.execute("SELECT * FROM t3f;")
 ---
@@ -927,7 +947,8 @@ box.execute("INSERT INTO t3g VALUES ('a');")
 ...
 box.execute("INSERT INTO t3g VALUES ('A');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3G_1' in space 'T3G'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3G_1' in space 'T3G'
 ...
 box.execute("SELECT * FROM t3g;")
 ---
diff --git a/test/sql/delete.result b/test/sql/delete.result
index 0bc389f..e27c79d 100644
--- a/test/sql/delete.result
+++ b/test/sql/delete.result
@@ -57,7 +57,8 @@ box.execute("DROP TABLE t1;");
 --
 box.execute("DELETE FROM t1;")
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.execute("CREATE TABLE t2 (s1 INT PRIMARY KEY);")
 ---
@@ -69,7 +70,8 @@ box.execute("CREATE TRIGGER t2 BEFORE INSERT ON t2 FOR EACH ROW BEGIN DELETE FRO
 ...
 box.execute("INSERT INTO t2 VALUES (0);")
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.execute("DROP TABLE t2;")
 ---
@@ -81,7 +83,8 @@ box.execute("DROP TABLE t2;")
 -- can't truncate system table.
 box.execute("TRUNCATE TABLE \"_fk_constraint\";")
 ---
-- error: Can't truncate a system space, space '_fk_constraint'
+- null
+- Can't truncate a system space, space '_fk_constraint'
 ...
 box.execute("CREATE TABLE t1(id INT PRIMARY KEY, a INT, b TEXT);")
 ---
@@ -128,8 +131,9 @@ box.execute("CREATE VIEW v1 AS SELECT * FROM t1;")
 ...
 box.execute("TRUNCATE TABLE v1;")
 ---
-- error: 'Failed to execute SQL statement: can not truncate space ''V1'' because space
-    is a view'
+- null
+- 'Failed to execute SQL statement: can not truncate space ''V1'' because space is
+  a view'
 ...
 -- Can't truncate table with FK.
 box.execute("CREATE TABLE t2(x INT PRIMARY KEY REFERENCES t1(id));")
@@ -138,8 +142,9 @@ box.execute("CREATE TABLE t2(x INT PRIMARY KEY REFERENCES t1(id));")
 ...
 box.execute("TRUNCATE TABLE t1;")
 ---
-- error: 'Failed to execute SQL statement: can not truncate space ''T1'' because other
-    objects depend on it'
+- null
+- 'Failed to execute SQL statement: can not truncate space ''T1'' because other objects
+  depend on it'
 ...
 -- Table triggers should be ignored.
 box.execute("DROP TABLE t2;")
diff --git a/test/sql/drop-table.result b/test/sql/drop-table.result
index 48b0010..af8fe38 100644
--- a/test/sql/drop-table.result
+++ b/test/sql/drop-table.result
@@ -32,7 +32,8 @@ box.execute("DROP TABLE zzzoobar")
 -- Table does not exist anymore. Should error here.
 box.execute("INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
 ---
-- error: Space 'ZZZOOBAR' does not exist
+- null
+- Space 'ZZZOOBAR' does not exist
 ...
 -- gh-3712: if space features sequence, data from _sequence_data
 -- must be deleted before space is dropped.
@@ -97,12 +98,14 @@ box.session.su('tmp')
 --
 box.execute('CREATE TABLE t1 (id INT PRIMARY KEY, a INT)')
 ---
-- error: Write access to space '_index' is denied for user 'tmp'
+- null
+- Write access to space '_index' is denied for user 'tmp'
 ...
 -- Error: no such table.
 box.execute('DROP TABLE t1')
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.session.su('admin')
 ---
@@ -138,7 +141,8 @@ box.session.su('tmp')
 --
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY AUTOINCREMENT, a INT UNIQUE, b INT UNIQUE, c INT UNIQUE, d INT UNIQUE)')
 ---
-- error: Write access to space '_sequence' is denied for user 'tmp'
+- null
+- Write access to space '_sequence' is denied for user 'tmp'
 ...
 box.session.su('admin')
 ---
@@ -180,8 +184,8 @@ box.execute('CREATE TABLE t3(a INTEGER PRIMARY KEY);')
 --
 box.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES t3, a INT UNIQUE, c TEXT REFERENCES t3);')
 ---
-- error: 'Failed to create foreign key constraint ''FK_CONSTRAINT_2_T4'': field type
-    mismatch'
+- null
+- 'Failed to create foreign key constraint ''FK_CONSTRAINT_2_T4'': field type mismatch'
 ...
 box.execute('DROP TABLE t3;')
 ---
diff --git a/test/sql/errinj.result b/test/sql/errinj.result
index cb15a83..f198d5f 100644
--- a/test/sql/errinj.result
+++ b/test/sql/errinj.result
@@ -189,11 +189,13 @@ box.error.injection.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("CREATE TRIGGER t1t INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES (1, 1); END;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.execute("CREATE INDEX t1a ON t1(a);")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.error.injection.set("ERRINJ_WAL_IO", false)
 ---
@@ -257,7 +259,8 @@ box.error.injection.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("DROP TRIGGER t1t;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.error.injection.set("ERRINJ_WAL_IO", false)
 ---
@@ -334,7 +337,8 @@ errinj.set("ERRINJ_WAL_IO", false)
 ...
 box.execute("INSERT INTO t3 VALUES (1, 2, 2);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 errinj.set("ERRINJ_WAL_IO", true)
 ---
@@ -342,7 +346,8 @@ errinj.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("ALTER TABLE t3 ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES t3;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 errinj.set("ERRINJ_WAL_IO", false)
 ---
@@ -366,7 +371,8 @@ box.execute("ALTER TABLE t3 ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES t3;")
 ...
 box.execute("INSERT INTO t3 VALUES(1, 1, 3);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 errinj.set("ERRINJ_WAL_IO", true)
 ---
@@ -374,11 +380,13 @@ errinj.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("ALTER TABLE t3 DROP CONSTRAINT fk1;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.execute("INSERT INTO t3 VALUES(1, 1, 3);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 errinj.set("ERRINJ_WAL_IO", false)
 ---
@@ -423,15 +431,18 @@ f = fiber.create(drop_table_yield)
 ...
 box.execute("SELECT * FROM t;")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("INSERT INTO t VALUES (2);")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("UPDATE t SET id = 2;")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 -- Finish drop space.
 errinj.set("ERRINJ_WAL_DELAY", false)
@@ -450,7 +461,8 @@ errinj.set("ERRINJ_SQL_NAME_NORMALIZATION", true)
 ...
 box.execute("CREATE TABLE hello (id INT primary key,x INT,y INT);")
 ---
-- error: Failed to allocate 6 bytes in sqlDbMallocRawNN for res
+- null
+- Failed to allocate 6 bytes in sqlDbMallocRawNN for res
 ...
 dummy_f = function(int) return 1 end
 ---
@@ -490,7 +502,8 @@ _ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<
 ...
 box.execute("INSERT INTO \"test\" VALUES(5);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
 ...
 errinj.set("ERRINJ_WAL_IO", true)
 ---
@@ -521,7 +534,8 @@ _ = box.space._ck_constraint:delete({s.id, 'CK_CONSTRAINT_01'})
 ...
 box.execute("INSERT INTO \"test\" VALUES(6);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
 ...
 errinj.set("ERRINJ_WAL_IO", false)
 ---
@@ -557,11 +571,13 @@ _ = box.space._ck_constraint:insert({s.id, 'Xgreater10', false, 'SQL', 'X > 10'}
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''Xgreater10'': X > 10'
+- null
+- 'Check constraint failed ''Xgreater10'': X > 10'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 10);")
 ---
-- error: 'Check constraint failed ''XlessY'': X < Y'
+- null
+- 'Check constraint failed ''XlessY'': X < Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 100);")
 ---
@@ -584,11 +600,13 @@ errinj.set("ERRINJ_WAL_IO", false)
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''Xgreater10'': X > 10'
+- null
+- 'Check constraint failed ''Xgreater10'': X > 10'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 10);")
 ---
-- error: 'Check constraint failed ''XlessY'': X < Y'
+- null
+- 'Check constraint failed ''XlessY'': X < Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 100);")
 ---
diff --git a/test/sql/foreign-keys.result b/test/sql/foreign-keys.result
index f3cca5c..38b0b14 100644
--- a/test/sql/foreign-keys.result
+++ b/test/sql/foreign-keys.result
@@ -181,7 +181,8 @@ t = box.space._fk_constraint:insert(t)
 --
 box.execute("DROP INDEX i1 on t1;")
 ---
-- error: 'Can''t modify space ''T1'': can not drop a referenced index'
+- null
+- 'Can''t modify space ''T1'': can not drop a referenced index'
 ...
 -- Referenced index can't be altered as well, if alter leads to
 -- rebuild of index (e.g. index still can be renamed).
@@ -395,21 +396,23 @@ box.execute('CREATE TABLE t1 (id INT PRIMARY KEY);')
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE RESTRICT);')
 ---
-- error: Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an
-    identifier.
+- null
+- Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an identifier.
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE CASCADE);')
 ---
-- error: Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an
-    identifier.
+- null
+- Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an identifier.
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON UPDATE RESTRICT ON DELETE RESTRICT);')
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE MATCH FULL);')
 ---
-- error: Keyword 'MATCH' is reserved. Please use double quotes if 'MATCH' is an identifier.
+- null
+- Keyword 'MATCH' is reserved. Please use double quotes if 'MATCH' is an identifier.
 ...
 box.space.T1:drop()
 ---
@@ -436,16 +439,18 @@ i1 = box.space.T2:create_index('I1')
 ...
 box.execute("ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (id) REFERENCES t2;")
 ---
-- error: 'Failed to create foreign key constraint ''FK'': foreign key refers to nonexistent
-    field'
+- null
+- 'Failed to create foreign key constraint ''FK'': foreign key refers to nonexistent
+  field'
 ...
 -- Make sure that if referenced columns (of parent space) are
 -- ommitted and parent space doesn't have PK, then error is raised.
 --
 box.execute("ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY (id) REFERENCES t1;")
 ---
-- error: 'Failed to create foreign key constraint ''FK'': referenced space doesn''t
-    feature PRIMARY KEY'
+- null
+- 'Failed to create foreign key constraint ''FK'': referenced space doesn''t feature
+  PRIMARY KEY'
 ...
 t1:drop()
 ---
diff --git a/test/sql/gh-2929-primary-key.result b/test/sql/gh-2929-primary-key.result
index 815b16e..021d037 100644
--- a/test/sql/gh-2929-primary-key.result
+++ b/test/sql/gh-2929-primary-key.result
@@ -20,19 +20,23 @@ box.execute("CREATE TABLE t1(a INT PRIMARY KEY, b INT UNIQUE)")
 ...
 box.execute("CREATE TABLE t2(a INT UNIQUE, b INT)")
 ---
-- error: 'Failed to create space ''T2'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T2'': PRIMARY KEY missing'
 ...
 box.execute("CREATE TABLE t3(a NUMBER)")
 ---
-- error: 'Failed to create space ''T3'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T3'': PRIMARY KEY missing'
 ...
 box.execute("CREATE TABLE t4(a NUMBER, b TEXT)")
 ---
-- error: 'Failed to create space ''T4'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T4'': PRIMARY KEY missing'
 ...
 box.execute("CREATE TABLE t5(a NUMBER, b NUMBER UNIQUE)")
 ---
-- error: 'Failed to create space ''T5'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T5'': PRIMARY KEY missing'
 ...
 box.execute("DROP TABLE t1")
 ---
@@ -43,5 +47,6 @@ box.execute("DROP TABLE t1")
 --
 box.execute("CREATE TABLE tx (a INT, PRIMARY KEY (b));")
 ---
-- error: Can’t resolve field 'B'
+- null
+- Can’t resolve field 'B'
 ...
diff --git a/test/sql/gh-2981-check-autoinc.result b/test/sql/gh-2981-check-autoinc.result
index f03858a..64ae64b 100644
--- a/test/sql/gh-2981-check-autoinc.result
+++ b/test/sql/gh-2981-check-autoinc.result
@@ -29,7 +29,8 @@ box.execute("insert into t1 values (18, null);")
 ...
 box.execute("insert into t1(s2) values (null);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': s1 <> 19'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': s1 <> 19'
 ...
 box.execute("insert into t2 values (18, null);")
 ---
@@ -37,7 +38,8 @@ box.execute("insert into t2 values (18, null);")
 ...
 box.execute("insert into t2(s2) values (null);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
 ...
 box.execute("insert into t2 values (24, null);")
 ---
@@ -45,7 +47,8 @@ box.execute("insert into t2 values (24, null);")
 ...
 box.execute("insert into t2(s2) values (null);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
 ...
 box.execute("insert into t3 values (9, null)")
 ---
@@ -53,7 +56,8 @@ box.execute("insert into t3 values (9, null)")
 ...
 box.execute("insert into t3(s2) values (null)")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T3'': s1 < 10'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T3'': s1 < 10'
 ...
 box.execute("DROP TABLE t1")
 ---
diff --git a/test/sql/gh-3613-idx-alter-update.result b/test/sql/gh-3613-idx-alter-update.result
index 20315df..ba323a6 100644
--- a/test/sql/gh-3613-idx-alter-update.result
+++ b/test/sql/gh-3613-idx-alter-update.result
@@ -33,7 +33,8 @@ box.snapshot()
 test_run:cmd('restart server default')
 box.execute('DROP INDEX i ON j3')
 ---
-- error: No index 'I' is defined in space 'J3'
+- null
+- No index 'I' is defined in space 'J3'
 ...
 box.execute('CREATE INDEX i ON j3 (s1)')
 ---
diff --git a/test/sql/gh-3888-values-blob-assert.result b/test/sql/gh-3888-values-blob-assert.result
index 81b0f52..768448c 100644
--- a/test/sql/gh-3888-values-blob-assert.result
+++ b/test/sql/gh-3888-values-blob-assert.result
@@ -17,30 +17,36 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 -- check 'VALUES' against typedef keywords (should fail)
 box.execute('VALUES(scalar)')
 ---
-- error: Syntax error near 'scalar'
+- null
+- Syntax error near 'scalar'
 ...
 box.execute('VALUES(float)')
 ---
-- error: Syntax error near 'float'
+- null
+- Syntax error near 'float'
 ...
 -- check 'SELECT' against typedef keywords (should fail)
 box.execute('SELECT scalar')
 ---
-- error: Syntax error near 'scalar'
+- null
+- Syntax error near 'scalar'
 ...
 box.execute('SELECT float')
 ---
-- error: Syntax error near 'float'
+- null
+- Syntax error near 'float'
 ...
 -- check 'VALUES' against ID (should fail)
 box.execute('VALUES(TheColumnName)')
 ---
-- error: Can’t resolve field 'THECOLUMNNAME'
+- null
+- Can’t resolve field 'THECOLUMNNAME'
 ...
 -- check 'SELECT' against ID (should fail)
 box.execute('SELECT TheColumnName')
 ---
-- error: Can’t resolve field 'THECOLUMNNAME'
+- null
+- Can’t resolve field 'THECOLUMNNAME'
 ...
 -- check 'VALUES' well-formed expression  (returns value)
 box.execute('VALUES(-0.5e-2)')
diff --git a/test/sql/icu-upper-lower.result b/test/sql/icu-upper-lower.result
index dc00c03..88266c8 100644
--- a/test/sql/icu-upper-lower.result
+++ b/test/sql/icu-upper-lower.result
@@ -276,13 +276,16 @@ test_run:cmd("setopt delimiter ''");
 -- Bad test cases
 box.execute("select upper('1', 2)")
 ---
-- error: wrong number of arguments to function UPPER()
+- null
+- wrong number of arguments to function UPPER()
 ...
 box.execute("select upper(\"1\")")
 ---
-- error: Can’t resolve field '1'
+- null
+- Can’t resolve field '1'
 ...
 box.execute("select upper()")
 ---
-- error: wrong number of arguments to function UPPER()
+- null
+- wrong number of arguments to function UPPER()
 ...
diff --git a/test/sql/insert-unique.result b/test/sql/insert-unique.result
index 236046f..1cf44c9 100644
--- a/test/sql/insert-unique.result
+++ b/test/sql/insert-unique.result
@@ -28,12 +28,14 @@ box.execute("INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- PK must be unique
 box.execute("INSERT INTO zoobar VALUES (112, 222, 'c3', 444)")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_ZOOBAR_1' in space 'ZOOBAR'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_ZOOBAR_1' in space 'ZOOBAR'
 ...
 -- Unique index must be respected
 box.execute("INSERT INTO zoobar VALUES (111, 223, 'c3', 444)")
 ---
-- error: Duplicate key exists in unique index 'ZOOBAR2' in space 'ZOOBAR'
+- null
+- Duplicate key exists in unique index 'ZOOBAR2' in space 'ZOOBAR'
 ...
 -- Cleanup
 box.execute("DROP INDEX zoobar2 ON zoobar")
diff --git a/test/sql/integer-overflow.result b/test/sql/integer-overflow.result
index a9a90f5..223ba02 100644
--- a/test/sql/integer-overflow.result
+++ b/test/sql/integer-overflow.result
@@ -14,7 +14,8 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.execute('SELECT (2147483647 * 2147483647 * 2147483647);')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT (-9223372036854775808 / -1);')
 ---
@@ -26,7 +27,8 @@ box.execute('SELECT (-9223372036854775808 / -1);')
 ...
 box.execute('SELECT (-9223372036854775808 - 1);')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT (9223372036854775807 + 1);')
 ---
@@ -38,11 +40,13 @@ box.execute('SELECT (9223372036854775807 + 1);')
 ...
 box.execute('SELECT (9223372036854775807 + 9223372036854775807 + 2);')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT 18446744073709551615 * 2;')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT (-9223372036854775807 * (-2));')
 ---
@@ -64,8 +68,9 @@ box.execute('SELECT 9223372036854775808;')
 ...
 box.execute('SELECT -9223372036854775809;')
 ---
-- error: Integer literal -9223372036854775809 exceeds the supported range [-9223372036854775808,
-    18446744073709551615]
+- null
+- Integer literal -9223372036854775809 exceeds the supported range [-9223372036854775808,
+  18446744073709551615]
 ...
 box.execute('SELECT 9223372036854775808 - 1;')
 ---
@@ -85,8 +90,9 @@ box.execute('SELECT 18446744073709551615;')
 ...
 box.execute('SELECT 18446744073709551616;')
 ---
-- error: Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808,
-    18446744073709551615]
+- null
+- Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808,
+  18446744073709551615]
 ...
 -- Test that CAST may also leads to overflow.
 --
@@ -100,7 +106,8 @@ box.execute('SELECT CAST(\'9223372036854775808\' AS INTEGER);')
 ...
 box.execute('SELECT CAST(\'18446744073709551616\' AS INTEGER);')
 ---
-- error: 'Type mismatch: can not convert 18446744073709551616 to integer'
+- null
+- 'Type mismatch: can not convert 18446744073709551616 to integer'
 ...
 -- Due to inexact represantation of large integers in terms of
 -- floating point numbers, numerics with value < INT64_MAX
@@ -110,7 +117,8 @@ box.execute('SELECT CAST(\'18446744073709551616\' AS INTEGER);')
 --
 box.execute('SELECT CAST(9223372036854775807.0 AS INTEGER);')
 ---
-- error: 'Type mismatch: can not convert 9.22337203685478e+18 to integer'
+- null
+- 'Type mismatch: can not convert 9.22337203685478e+18 to integer'
 ...
 -- gh-3810: make sure that if space contains integers in range
 -- [INT64_MAX, UINT64_MAX], they are handled inside SQL in a
diff --git a/test/sql/message-func-indexes.result b/test/sql/message-func-indexes.result
index eb2d6c7..69e3ee0 100644
--- a/test/sql/message-func-indexes.result
+++ b/test/sql/message-func-indexes.result
@@ -21,7 +21,8 @@ box.execute("CREATE TABLE t2(object INTEGER PRIMARY KEY, price INTEGER, count IN
 -- should return certain message.
 box.execute("CREATE INDEX i1 ON t1(a+1)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 box.execute("CREATE INDEX i2 ON t1(a)")
 ---
@@ -29,7 +30,8 @@ box.execute("CREATE INDEX i2 ON t1(a)")
 ...
 box.execute("CREATE INDEX i3 ON t2(price + 100)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 box.execute("CREATE INDEX i4 ON t2(price)")
 ---
@@ -37,11 +39,13 @@ box.execute("CREATE INDEX i4 ON t2(price)")
 ...
 box.execute("CREATE INDEX i5 ON t2(count + 1)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 box.execute("CREATE INDEX i6 ON t2(count * price)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 -- Cleaning up.
 box.execute("DROP TABLE t1")
diff --git a/test/sql/misc.result b/test/sql/misc.result
index bc8b10e..e9bfe89 100644
--- a/test/sql/misc.result
+++ b/test/sql/misc.result
@@ -19,13 +19,13 @@ box.execute('select 1;')
 ...
 box.execute('select 1; select 2;')
 ---
-- error: Keyword 'select' is reserved. Please use double quotes if 'select' is an
-    identifier.
+- null
+- Keyword 'select' is reserved. Please use double quotes if 'select' is an identifier.
 ...
 box.execute('create table t1 (id INT primary key); select 100;')
 ---
-- error: Keyword 'select' is reserved. Please use double quotes if 'select' is an
-    identifier.
+- null
+- Keyword 'select' is reserved. Please use double quotes if 'select' is an identifier.
 ...
 box.space.t1 == nil
 ---
@@ -33,35 +33,40 @@ box.space.t1 == nil
 ...
 box.execute(';')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 box.execute('')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 box.execute('     ;')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 box.execute('\n\n\n\t\t\t   ')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 -- gh-3820: only table constraints can have a name.
 --
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b INTEGER CONSTRAINT c1 NULL)')
 ---
-- error: Keyword 'NULL' is reserved. Please use double quotes if 'NULL' is an identifier.
+- null
+- Keyword 'NULL' is reserved. Please use double quotes if 'NULL' is an identifier.
 ...
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b INTEGER CONSTRAINT c1 DEFAULT 300)')
 ---
-- error: Keyword 'DEFAULT' is reserved. Please use double quotes if 'DEFAULT' is an
-    identifier.
+- null
+- Keyword 'DEFAULT' is reserved. Please use double quotes if 'DEFAULT' is an identifier.
 ...
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b TEXT CONSTRAINT c1 COLLATE "binary")')
 ---
-- error: Keyword 'COLLATE' is reserved. Please use double quotes if 'COLLATE' is an
-    identifier.
+- null
+- Keyword 'COLLATE' is reserved. Please use double quotes if 'COLLATE' is an identifier.
 ...
 -- Make sure that type of literals in meta complies with its real
 -- type. For instance, typeof(0.5) is number, not integer.
diff --git a/test/sql/no-pk-space.result b/test/sql/no-pk-space.result
index f4f6059..025f363 100644
--- a/test/sql/no-pk-space.result
+++ b/test/sql/no-pk-space.result
@@ -19,19 +19,23 @@ s = box.schema.create_space('test', {format = format})
 ...
 box.execute("SELECT * FROM \"test\";")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("INSERT INTO \"test\" VALUES (1);")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("DELETE FROM \"test\";")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("UPDATE \"test\" SET id = 3;")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 s:drop()
 ---
@@ -54,7 +58,8 @@ box.space.T1:drop()
 ...
 box.execute("SELECT * FROM v1;")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.space.V1:drop()
 ---
diff --git a/test/sql/on-conflict.result b/test/sql/on-conflict.result
index 2c3dfa7..6851e21 100644
--- a/test/sql/on-conflict.result
+++ b/test/sql/on-conflict.result
@@ -14,57 +14,69 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT ABORT)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE q (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT FAIL)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE p (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT IGNORE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE g (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT REPLACE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE e (id INTEGER PRIMARY KEY ON CONFLICT REPLACE, v INTEGER)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE t1(a INT PRIMARY KEY ON CONFLICT REPLACE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE t2(a INT PRIMARY KEY ON CONFLICT IGNORE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 -- CHECK constraint is illegal with REPLACE option.
 --
 box.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER CHECK (a > 5) ON CONFLICT REPLACE);")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 --
 -- gh-3473: Primary key can't be declared with NULL.
 --
 box.execute("CREATE TABLE te17 (s1 INT NULL PRIMARY KEY NOT NULL);")
 ---
-- error: Primary index of space 'TE17' can not contain nullable parts
+- null
+- Primary index of space 'TE17' can not contain nullable parts
 ...
 box.execute("CREATE TABLE te17 (s1 INT NULL PRIMARY KEY);")
 ---
-- error: Primary index of space 'TE17' can not contain nullable parts
+- null
+- Primary index of space 'TE17' can not contain nullable parts
 ...
 box.execute("CREATE TABLE test (a int PRIMARY KEY, b int NULL ON CONFLICT IGNORE);")
 ---
-- error: 'Failed to execute SQL statement: NULL declaration for column ''B'' of table
-    ''TEST'' has been already set to ''none'''
+- null
+- 'Failed to execute SQL statement: NULL declaration for column ''B'' of table ''TEST''
+  has been already set to ''none'''
 ...
 box.execute("CREATE TABLE test (a int, b int NULL, c int, PRIMARY KEY(a, b, c))")
 ---
-- error: Primary index of space 'TEST' can not contain nullable parts
+- null
+- Primary index of space 'TEST' can not contain nullable parts
 ...
 -- Several NOT NULL REPLACE constraints work
 --
diff --git a/test/sql/persistency.result b/test/sql/persistency.result
index fcb5d23..f8f992c 100644
--- a/test/sql/persistency.result
+++ b/test/sql/persistency.result
@@ -31,7 +31,8 @@ box.execute("INSERT INTO foobar VALUES (1000, 'foobar')")
 ...
 box.execute("INSERT INTO foobar VALUES (1, 'duplicate')")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
 ...
 -- simple select
 box.execute("SELECT bar, foo, 42, 'awesome' FROM foobar")
@@ -369,7 +370,8 @@ box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"");
 -- ... functional
 box.execute("INSERT INTO foobar VALUES ('foobar trigger test', 8888)")
 ---
-- error: 'Type mismatch: can not convert foobar trigger test to integer'
+- null
+- 'Type mismatch: can not convert foobar trigger test to integer'
 ...
 box.execute("SELECT * FROM barfoo WHERE foo = 9999");
 ---
@@ -400,7 +402,8 @@ box.execute("DROP TRIGGER tfoobar")
 -- Should error
 box.execute("DROP TRIGGER tfoobar")
 ---
-- error: Trigger 'TFOOBAR' doesn't exist
+- null
+- Trigger 'TFOOBAR' doesn't exist
 ...
 -- Should be empty
 box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"")
@@ -415,7 +418,8 @@ box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"")
 -- prove barfoo2 still exists
 box.execute("INSERT INTO barfoo VALUES ('xfoo', 1)")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
 ...
 box.execute("SELECT * FROM barfoo")
 ---
diff --git a/test/sql/row-count.result b/test/sql/row-count.result
index ed7e319..fb96e21 100644
--- a/test/sql/row-count.result
+++ b/test/sql/row-count.result
@@ -272,7 +272,8 @@ box.execute("SELECT ROW_COUNT();")
 ...
 box.execute("COMMIT;")
 ---
-- error: 'Failed to execute SQL statement: cannot commit - no transaction is active'
+- null
+- 'Failed to execute SQL statement: cannot commit - no transaction is active'
 ...
 box.execute("SELECT ROW_COUNT();")
 ---
diff --git a/test/sql/savepoints.result b/test/sql/savepoints.result
index d20e0ed..7895717 100644
--- a/test/sql/savepoints.result
+++ b/test/sql/savepoints.result
@@ -14,15 +14,18 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.execute('SAVEPOINT t1;');
 ---
-- error: No active transaction
+- null
+- No active transaction
 ...
 box.execute('RELEASE SAVEPOINT t1;');
 ---
-- error: No active transaction
+- null
+- No active transaction
 ...
 box.execute('ROLLBACK TO SAVEPOINT t1;');
 ---
-- error: No active transaction
+- null
+- No active transaction
 ...
 box.begin() box.execute('SAVEPOINT t1;') box.execute('RELEASE SAVEPOINT t1;') box.commit();
 ---
@@ -61,13 +64,16 @@ release_sv_fail = function()
     box.execute('SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t1;')
-    box.execute('ROLLBACK TO t1;')
+    local _, err = box.execute('ROLLBACK TO t1;')
+    if err ~= nil then
+        return err
+    end
 end;
 ---
 ...
 release_sv_fail();
 ---
-- error: 'Can not rollback to savepoint: the savepoint does not exist'
+- 'Can not rollback to savepoint: the savepoint does not exist'
 ...
 box.commit();
 ---
diff --git a/test/sql/savepoints.test.lua b/test/sql/savepoints.test.lua
index b4c6fee..d96b046 100644
--- a/test/sql/savepoints.test.lua
+++ b/test/sql/savepoints.test.lua
@@ -37,7 +37,10 @@ release_sv_fail = function()
     box.execute('SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t1;')
-    box.execute('ROLLBACK TO t1;')
+    local _, err = box.execute('ROLLBACK TO t1;')
+    if err ~= nil then
+        return err
+    end
 end;
 release_sv_fail();
 box.commit();
diff --git a/test/sql/transition.result b/test/sql/transition.result
index e779474..9738092 100644
--- a/test/sql/transition.result
+++ b/test/sql/transition.result
@@ -28,7 +28,8 @@ box.execute("INSERT INTO foobar VALUES (1000, 'foobar')")
 ...
 box.execute("INSERT INTO foobar VALUES (1, 'duplicate')")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
 ...
 -- simple select
 box.execute("SELECT bar, foo, 42, 'awesome' FROM foobar")
@@ -311,7 +312,8 @@ box.execute("INSERT INTO barfoo VALUES ('foobar', 1000)")
 -- prove barfoo2 was created
 box.execute("INSERT INTO barfoo VALUES ('xfoo', 1)")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
 ...
 box.execute("SELECT foo, bar FROM barfoo")
 ---
@@ -383,8 +385,8 @@ box.execute("DROP TABLE barfoo")
 -- attempt to create a table lacking PRIMARY KEY
 box.execute("CREATE TABLE without_rowid_lacking_primary_key(x SCALAR)")
 ---
-- error: 'Failed to create space ''WITHOUT_ROWID_LACKING_PRIMARY_KEY'': PRIMARY KEY
-    missing'
+- null
+- 'Failed to create space ''WITHOUT_ROWID_LACKING_PRIMARY_KEY'': PRIMARY KEY missing'
 ...
 -- create a table with implicit indices (used to SEGFAULT)
 box.execute("CREATE TABLE implicit_indices(a INT PRIMARY KEY,b INT,c INT,d TEXT UNIQUE)")
diff --git a/test/sql/transitive-transactions.result b/test/sql/transitive-transactions.result
index ee9b421..29c7316 100644
--- a/test/sql/transitive-transactions.result
+++ b/test/sql/transitive-transactions.result
@@ -39,13 +39,16 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y) D
 fk_violation_1 = function()
     box.begin()
     box.execute('INSERT INTO child VALUES (1, 1);')
-    box.execute('COMMIT;')
+    local _, err = box.execute('COMMIT;')
+    if err ~= nil then
+        return err
+    end
 end;
 ---
 ...
 fk_violation_1();
 ---
-- error: 'Can not commit transaction: deferred foreign keys violations are not resolved'
+- 'Can not commit transaction: deferred foreign keys violations are not resolved'
 ...
 box.space.CHILD:select();
 ---
@@ -92,7 +95,10 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y))'
 
 fk_defer = function()
     box.begin()
-    box.execute('INSERT INTO child VALUES (1, 2);')
+    local _, err = box.execute('INSERT INTO child VALUES (1, 2);')
+    if err ~= nil then
+        return err
+    end
     box.execute('INSERT INTO parent VALUES (2, 2);')
     box.commit()
 end;
@@ -100,7 +106,7 @@ end;
 ...
 fk_defer();
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.space.CHILD:select();
 ---
diff --git a/test/sql/transitive-transactions.test.lua b/test/sql/transitive-transactions.test.lua
index 54f1273..4633f07 100644
--- a/test/sql/transitive-transactions.test.lua
+++ b/test/sql/transitive-transactions.test.lua
@@ -19,7 +19,10 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y) D
 fk_violation_1 = function()
     box.begin()
     box.execute('INSERT INTO child VALUES (1, 1);')
-    box.execute('COMMIT;')
+    local _, err = box.execute('COMMIT;')
+    if err ~= nil then
+        return err
+    end
 end;
 fk_violation_1();
 box.space.CHILD:select();
@@ -49,7 +52,10 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y))'
 
 fk_defer = function()
     box.begin()
-    box.execute('INSERT INTO child VALUES (1, 2);')
+    local _, err = box.execute('INSERT INTO child VALUES (1, 2);')
+    if err ~= nil then
+        return err
+    end
     box.execute('INSERT INTO parent VALUES (2, 2);')
     box.commit()
 end;
diff --git a/test/sql/triggers.result b/test/sql/triggers.result
index 76e87c8..9dfe981 100644
--- a/test/sql/triggers.result
+++ b/test/sql/triggers.result
@@ -322,7 +322,8 @@ box.execute("INSERT INTO n VALUES (0, '',null);")
 ...
 box.execute("UPDATE m SET s1 = 'The Rain In Spain';")
 ---
-- error: A multi-statement transaction can not use multiple storage engines
+- null
+- A multi-statement transaction can not use multiple storage engines
 ...
 -- ANALYZE banned in gh-4069
 -- box.sql.execute("ANALYZE m;")
@@ -365,7 +366,8 @@ box.execute("INSERT INTO n VALUES (0, '',null);")
 ...
 box.execute("UPDATE m SET s1 = 'The Rain In Spain';")
 ---
-- error: A multi-statement transaction can not use multiple storage engines
+- null
+- A multi-statement transaction can not use multiple storage engines
 ...
 -- ANALYZE banned in gh-4069
 -- box.sql.execute("ANALYZE n;")
@@ -408,7 +410,8 @@ box.execute("INSERT INTO test VALUES (1)")
 ...
 box.execute("SELECT * FROM test2")
 ---
-- error: A multi-statement transaction can not use multiple storage engines
+- null
+- A multi-statement transaction can not use multiple storage engines
 ...
 box.execute("ROLLBACK;")
 ---
@@ -483,7 +486,8 @@ space_id = box.space.T1.id
 ...
 box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW WHEN new.a = ? BEGIN SELECT 1; END;")
 ---
-- error: bindings are not allowed in DDL
+- null
+- bindings are not allowed in DDL
 ...
 tuple = {"TR1", space_id, {sql = [[CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW WHEN new.a = ? BEGIN SELECT 1; END;]]}}
 ---
@@ -508,8 +512,8 @@ space_id = box.space.T1.id
 ...
 box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN ; END;")
 ---
-- error: FOR EACH STATEMENT triggers are not implemented, please supply FOR EACH ROW
-    clause
+- null
+- FOR EACH STATEMENT triggers are not implemented, please supply FOR EACH ROW clause
 ...
 box.execute("DROP TABLE t1;")
 ---
@@ -539,7 +543,8 @@ box.session.su('tester')
 --
 box.execute([[CREATE TRIGGER r1 AFTER INSERT ON t1 FOR EACH ROW BEGIN SELECT 1; END; ]])
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.session.su('admin')
 ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 780a23d..604f541 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -8,26 +8,28 @@ test_run = env.new()
 --
 box.execute("CREATE TABLE t1 (id PRIMARY KEY);")
 ---
-- error: Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an
-    identifier.
+- null
+- Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an identifier.
 ...
 box.execute("CREATE TABLE t1 (a, id INT PRIMARY KEY);")
 ---
-- error: Syntax error near ','
+- null
+- Syntax error near ','
 ...
 box.execute("CREATE TABLE t1 (id PRIMARY KEY, a INT);")
 ---
-- error: Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an
-    identifier.
+- null
+- Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an identifier.
 ...
 box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a);")
 ---
-- error: Syntax error near ')'
+- null
+- Syntax error near ')'
 ...
 box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b UNIQUE);")
 ---
-- error: Keyword 'UNIQUE' is reserved. Please use double quotes if 'UNIQUE' is an
-    identifier.
+- null
+- Keyword 'UNIQUE' is reserved. Please use double quotes if 'UNIQUE' is an identifier.
 ...
 -- gh-3104: real type is stored in space format.
 --
@@ -152,33 +154,40 @@ sp:drop()
 --
 box.execute("SELECT 'abc' || 1;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
 ...
 box.execute("SELECT 'abc' || 1.123;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got REAL'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got REAL'
 ...
 box.execute("SELECT 1 || 'abc';")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
 ...
 box.execute("SELECT 1.123 || 'abc';")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got REAL'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got REAL'
 ...
 box.execute("SELECt 'a' || 'b' || 1;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
 ...
 -- What is more, they must be of the same type.
 --
 box.execute("SELECT 'abc' || randomblob(5);")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT randomblob(5) || 'x';")
 ---
-- error: 'Inconsistent types: expected BLOB got TEXT'
+- null
+- 'Inconsistent types: expected BLOB got TEXT'
 ...
 -- Result of BLOBs concatenation must be BLOB.
 --
@@ -202,15 +211,18 @@ box.execute("INSERT INTO t1 VALUES (randomblob(5));")
 ...
 box.execute("SELECT * FROM t1 WHERE s LIKE 'blob';")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT * FROM t1 WHERE 'blob' LIKE s;")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT * FROM t1 WHERE 'blob' LIKE x'0000';")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT s LIKE NULL FROM t1;")
 ---
@@ -230,11 +242,13 @@ box.execute("INSERT INTO t1 VALUES (1);")
 ...
 box.execute("SELECT * FROM t1 WHERE s LIKE 'int';")
 ---
-- error: 'Inconsistent types: expected TEXT got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT got UNSIGNED'
 ...
 box.execute("SELECT * FROM t1 WHERE 'int' LIKE 4;")
 ---
-- error: 'Inconsistent types: expected TEXT got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT got UNSIGNED'
 ...
 box.execute("SELECT NULL LIKE s FROM t1;")
 ---
@@ -355,15 +369,18 @@ box.execute("SELECT unknown = true;")
 ...
 box.execute("SELECT 1 = true;")
 ---
-- error: 'Type mismatch: can not convert UNSIGNED to boolean'
+- null
+- 'Type mismatch: can not convert UNSIGNED to boolean'
 ...
 box.execute("SELECT 'abc' = true;")
 ---
-- error: 'Type mismatch: can not convert TEXT to boolean'
+- null
+- 'Type mismatch: can not convert TEXT to boolean'
 ...
 box.execute("SELECT 1.123 > true;")
 ---
-- error: 'Type mismatch: can not convert REAL to boolean'
+- null
+- 'Type mismatch: can not convert REAL to boolean'
 ...
 box.execute("SELECT true IN (1, 'abc', true)")
 ---
@@ -383,31 +400,37 @@ box.execute("SELECT true IN (1, 'abc', false)")
 ...
 box.execute("SELECT 1 LIMIT true;")
 ---
-- error: 'Failed to execute SQL statement: Only positive integers are allowed in the
-    LIMIT clause'
+- null
+- 'Failed to execute SQL statement: Only positive integers are allowed in the LIMIT
+  clause'
 ...
 box.execute("SELECT 1 LIMIT 1 OFFSET true;")
 ---
-- error: 'Failed to execute SQL statement: Only positive integers are allowed in the
-    OFFSET clause'
+- null
+- 'Failed to execute SQL statement: Only positive integers are allowed in the OFFSET
+  clause'
 ...
 box.execute("SELECT 'abc' || true;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got BOOLEAN'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got BOOLEAN'
 ...
 -- Boolean can take part in arithmetic operations.
 --
 box.execute("SELECT true + false;")
 ---
-- error: 'Type mismatch: can not convert false to numeric'
+- null
+- 'Type mismatch: can not convert false to numeric'
 ...
 box.execute("SELECT true * 1;")
 ---
-- error: 'Type mismatch: can not convert true to numeric'
+- null
+- 'Type mismatch: can not convert true to numeric'
 ...
 box.execute("SELECT false / 0;")
 ---
-- error: 'Type mismatch: can not convert false to numeric'
+- null
+- 'Type mismatch: can not convert false to numeric'
 ...
 box.execute("SELECT not true;")
 ---
@@ -419,19 +442,23 @@ box.execute("SELECT not true;")
 ...
 box.execute("SELECT ~true;")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.execute("SELECT -true;")
 ---
-- error: 'Type mismatch: can not convert true to numeric'
+- null
+- 'Type mismatch: can not convert true to numeric'
 ...
 box.execute("SELECT true << 1;")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.execute("SELECT true | 1;")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.execute("SELECT true and false;")
 ---
@@ -553,22 +580,26 @@ box.execute("SELECT b FROM t GROUP BY b LIMIT 1;")
 ...
 box.execute("SELECT b FROM t LIMIT true;")
 ---
-- error: 'Failed to execute SQL statement: Only positive integers are allowed in the
-    LIMIT clause'
+- null
+- 'Failed to execute SQL statement: Only positive integers are allowed in the LIMIT
+  clause'
 ...
 -- Most of aggregates don't accept boolean arguments.
 --
 box.execute("SELECT sum(b) FROM t;")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT avg(b) FROM t;")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT total(b) FROM t;")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT min(b) FROM t;")
 ---
@@ -626,7 +657,8 @@ box.execute("SELECT upper(b) FROM t;")
 ...
 box.execute("SELECT abs(b) FROM t;")
 ---
-- error: 'Inconsistent types: expected number got boolean'
+- null
+- 'Inconsistent types: expected number got boolean'
 ...
 box.execute("SELECT typeof(b) FROM t;")
 ---
@@ -721,7 +753,8 @@ box.execute("ALTER TABLE t ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES parent
 ...
 box.execute("INSERT INTO t VALUES (1, true);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.execute("INSERT INTO parent VALUES (1, true);")
 ---
@@ -744,7 +777,8 @@ box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a BOOLEAN CHECK (a = true));")
 ...
 box.execute("INSERT INTO t1 VALUES (1, false);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a = true'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a = true'
 ...
 box.execute("INSERT INTO t1 VALUES (1, true);")
 ---
@@ -801,7 +835,8 @@ box.execute("SELECT CAST(true AS TEXT);")
 ...
 box.execute("SELECT CAST(true AS NUMBER);")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT CAST(true AS SCALAR);")
 ---
@@ -845,7 +880,8 @@ box.execute("SELECT CAST(0.00000001 AS BOOLEAN);")
 ...
 box.execute("SELECT CAST('abc' AS BOOLEAN);")
 ---
-- error: 'Type mismatch: can not convert abc to boolean'
+- null
+- 'Type mismatch: can not convert abc to boolean'
 ...
 box.execute("SELECT CAST('  TrUe' AS BOOLEAN);")
 ---
@@ -865,11 +901,13 @@ box.execute("SELECT CAST('  falsE    ' AS BOOLEAN);")
 ...
 box.execute("SELECT CAST('  fals' AS BOOLEAN);")
 ---
-- error: 'Type mismatch: can not convert   fals to boolean'
+- null
+- 'Type mismatch: can not convert   fals to boolean'
 ...
 box.execute("SELECT CAST(X'4D6564766564' AS BOOLEAN);")
 ---
-- error: 'Type mismatch: can not convert Medved to boolean'
+- null
+- 'Type mismatch: can not convert Medved to boolean'
 ...
 -- Make sure that SCALAR can handle boolean values.
 --
@@ -895,11 +933,13 @@ box.execute("INSERT INTO t1 VALUES (3, 'abc'), (4, 12.5);")
 ...
 box.execute("SELECT s FROM t1 WHERE s = true;")
 ---
-- error: 'Type mismatch: can not convert TEXT to boolean'
+- null
+- 'Type mismatch: can not convert TEXT to boolean'
 ...
 box.execute("SELECT s FROM t1 WHERE s < true;")
 ---
-- error: 'Type mismatch: can not convert TEXT to boolean'
+- null
+- 'Type mismatch: can not convert TEXT to boolean'
 ...
 box.execute("SELECT s FROM t1 WHERE s IN (true, 1, 'abcd')")
 ---
@@ -924,7 +964,8 @@ box.execute("CREATE TABLE t1 (id INT PRIMARY KEY);")
 ...
 box.execute("INSERT INTO t1 VALUES (true);")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.space.T1:drop()
 ---
@@ -979,19 +1020,23 @@ box.execute("INSERT INTO tboolean VALUES (TRUE);")
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = x'44';")
 ---
-- error: 'Type mismatch: can not convert D to boolean'
+- null
+- 'Type mismatch: can not convert D to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 'abc';")
 ---
-- error: 'Type mismatch: can not convert abc to boolean'
+- null
+- 'Type mismatch: can not convert abc to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1;")
 ---
-- error: 'Type mismatch: can not convert UNSIGNED to boolean'
+- null
+- 'Type mismatch: can not convert UNSIGNED to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1.123;")
 ---
-- error: 'Type mismatch: can not convert REAL to boolean'
+- null
+- 'Type mismatch: can not convert REAL to boolean'
 ...
 box.space.TBOOLEAN:drop()
 ---
@@ -1268,7 +1313,8 @@ box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
 ...
 box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")
 ---
-- error: 'Type mismatch: can not convert 18446744073709551616 to integer'
+- null
+- 'Type mismatch: can not convert 18446744073709551616 to integer'
 ...
 box.execute("SELECT CAST('18446744073' || '709551615' AS INTEGER);")
 ---
@@ -1320,7 +1366,8 @@ box.execute("SELECT 18446744073709551615 / -9223372036854775808;")
 ...
 box.execute("SELECT 0 - 18446744073709551610;")
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute("CREATE TABLE t (id INT PRIMARY KEY, i INT);")
 ---
@@ -1378,7 +1425,8 @@ box.execute("SELECT i FROM t ORDER BY i;")
 ...
 box.execute("SELECT i FROM t ORDER BY -i;")
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute("SELECT i FROM t ORDER BY i LIMIT 1;")
 ---
@@ -1569,7 +1617,8 @@ box.execute("ALTER TABLE t ADD CONSTRAINT fk1 FOREIGN KEY (i) REFERENCES parent
 ...
 box.execute("INSERT INTO t VALUES (1, 18446744073709551615);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.execute("INSERT INTO parent VALUES (2, 18446744073709551615);")
 ---
@@ -1595,11 +1644,13 @@ box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT CHECK (a > 1844674407370
 ...
 box.execute("INSERT INTO t1 VALUES (1, 18446744073709551611);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
 ...
 box.execute("INSERT INTO t1 VALUES (1, -1);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
 ...
 box.space.T1:drop()
 ---
@@ -1692,7 +1743,8 @@ box.execute("INSERT INTO t1 VALUES (0), (1), (2);")
 ...
 box.execute("INSERT INTO t1 VALUES (-3);")
 ---
-- error: 'Type mismatch: can not convert -3 to unsigned'
+- null
+- 'Type mismatch: can not convert -3 to unsigned'
 ...
 box.execute("SELECT id FROM t1;")
 ---
@@ -1714,7 +1766,8 @@ box.execute("SELECT CAST(123 AS UNSIGNED);")
 ...
 box.execute("SELECT CAST(-123 AS UNSIGNED);")
 ---
-- error: 'Type mismatch: can not convert -123 to unsigned'
+- null
+- 'Type mismatch: can not convert -123 to unsigned'
 ...
 box.execute("SELECT CAST(1.5 AS UNSIGNED);")
 ---
@@ -1726,7 +1779,8 @@ box.execute("SELECT CAST(1.5 AS UNSIGNED);")
 ...
 box.execute("SELECT CAST(-1.5 AS UNSIGNED);")
 ---
-- error: 'Type mismatch: can not convert -1 to unsigned'
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
 ...
 box.execute("SELECT CAST(true AS UNSIGNED);")
 ---
@@ -1746,7 +1800,8 @@ box.execute("SELECT CAST('123' AS UNSIGNED);")
 ...
 box.execute("SELECT CAST('-123' AS UNSIGNED);")
 ---
-- error: 'Type mismatch: can not convert -123 to unsigned'
+- null
+- 'Type mismatch: can not convert -123 to unsigned'
 ...
 box.space.T1:drop()
 ---
diff --git a/test/sql/view.result b/test/sql/view.result
index 4f02032..d845df8 100644
--- a/test/sql/view.result
+++ b/test/sql/view.result
@@ -22,7 +22,8 @@ box.execute("CREATE VIEW v1 AS SELECT a+b FROM t1;");
 -- View can't have any indexes.
 box.execute("CREATE INDEX i1 on v1(a);");
 ---
-- error: 'Can''t create or modify index ''I1'' in space ''V1'': views can not be indexed'
+- null
+- 'Can''t create or modify index ''I1'' in space ''V1'': views can not be indexed'
 ...
 v1 = box.space.V1;
 ---
@@ -78,8 +79,8 @@ box.schema.create_space('view', {view = true})
 -- Space referenced by a view can't be renamed.
 box.execute("ALTER TABLE t1 RENAME TO new_name;")
 ---
-- error: 'Can''t modify space ''T1'': can not rename space which is referenced by
-    view'
+- null
+- 'Can''t modify space ''T1'': can not rename space which is referenced by view'
 ...
 -- View can be created via straight insertion into _space.
 sp = box.schema.create_space('test');
@@ -148,7 +149,8 @@ box.execute("CREATE VIEW v2 AS SELECT * FROM t2;");
 ...
 box.execute("DROP TABLE t2;");
 ---
-- error: 'Can''t drop space ''T2'': other views depend on this space'
+- null
+- 'Can''t drop space ''T2'': other views depend on this space'
 ...
 sp = box.space._space:get{box.space.T2.id};
 ---
@@ -158,7 +160,8 @@ sp = box.space._space:replace(sp);
 ...
 box.execute("DROP TABLE t2;");
 ---
-- error: 'Can''t drop space ''T2'': other views depend on this space'
+- null
+- 'Can''t drop space ''T2'': other views depend on this space'
 ...
 box.execute("DROP VIEW v2;");
 ---
@@ -216,7 +219,8 @@ box.execute("CREATE VIEW bv (wombat) AS VALUES ((SELECT 'k' FROM b));")
 ...
 box.execute("DROP TABLE b;")
 ---
-- error: 'Can''t drop space ''B'': other views depend on this space'
+- null
+- 'Can''t drop space ''B'': other views depend on this space'
 ...
 box.execute("DROP VIEW bv;")
 ---
@@ -240,7 +244,8 @@ box.execute("CREATE VIEW bcv AS SELECT * FROM b WHERE s1 IN (SELECT * FROM c);")
 ...
 box.execute("DROP TABLE c;")
 ---
-- error: 'Can''t drop space ''C'': other views depend on this space'
+- null
+- 'Can''t drop space ''C'': other views depend on this space'
 ...
 box.execute("DROP VIEW bcv;")
 ---
@@ -260,7 +265,8 @@ box.execute("CREATE VIEW bcv(x, y) AS VALUES((SELECT 'k' FROM b), (VALUES((SELEC
 ...
 box.execute("DROP TABLE c;")
 ---
-- error: 'Can''t drop space ''C'': other views depend on this space'
+- null
+- 'Can''t drop space ''C'': other views depend on this space'
 ...
 box.space.BCV:drop()
 ---
@@ -291,7 +297,8 @@ box.execute("CREATE VIEW v2 AS SELECT * FROM t2;")
 test_run:cmd('restart server default')
 box.execute("DROP TABLE t2;")
 ---
-- error: 'Can''t drop space ''T2'': other views depend on this space'
+- null
+- 'Can''t drop space ''T2'': other views depend on this space'
 ...
 box.execute("SELECT * FROM v2;")
 ---

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error() imeevma
@ 2019-07-31 15:23   ` Alexander Turenko
  2019-07-31 15:39     ` Konstantin Osipov
  2019-07-31 15:40     ` Vladislav Shpilevoy
  2019-07-31 17:15   ` Vladislav Shpilevoy
  1 sibling, 2 replies; 17+ messages in thread
From: Alexander Turenko @ 2019-07-31 15:23 UTC (permalink / raw)
  To: imeevma; +Cc: v.shpilevoy, kostja, tarantool-patches

> +/**
> + * Return nil as the first return value and an error as the
> + * second. The error is received using box_error_last().
> + *
> + * @param L Lua stack.
> + */
> +LUA_API int
> +luaT_return_error(lua_State *L);

Maybe let the name be a bit more explicit, say,
luaT_push_conventional_error(struct lua_State *L)?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 15:23   ` [tarantool-patches] " Alexander Turenko
@ 2019-07-31 15:39     ` Konstantin Osipov
  2019-07-31 15:40     ` Vladislav Shpilevoy
  1 sibling, 0 replies; 17+ messages in thread
From: Konstantin Osipov @ 2019-07-31 15:39 UTC (permalink / raw)
  To: Alexander Turenko; +Cc: imeevma, v.shpilevoy, tarantool-patches

* Alexander Turenko <alexander.turenko@tarantool.org> [19/07/31 18:37]:
> > +/**
> > + * Return nil as the first return value and an error as the
> > + * second. The error is received using box_error_last().
> > + *
> > + * @param L Lua stack.
> > + */
> > +LUA_API int
> > +luaT_return_error(lua_State *L);
> 
> Maybe let the name be a bit more explicit, say,
> luaT_push_conventional_error(struct lua_State *L)?

Ugh. What is conventional? Conventions change.

-- 
Konstantin Osipov, Moscow, Russia

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 15:23   ` [tarantool-patches] " Alexander Turenko
  2019-07-31 15:39     ` Konstantin Osipov
@ 2019-07-31 15:40     ` Vladislav Shpilevoy
  2019-07-31 16:20       ` Imeev Mergen
  1 sibling, 1 reply; 17+ messages in thread
From: Vladislav Shpilevoy @ 2019-07-31 15:40 UTC (permalink / raw)
  To: tarantool-patches, Alexander Turenko, imeevma; +Cc: kostja



On 31/07/2019 17:23, Alexander Turenko wrote:
>> +/**
>> + * Return nil as the first return value and an error as the
>> + * second. The error is received using box_error_last().
>> + *
>> + * @param L Lua stack.
>> + */
>> +LUA_API int
>> +luaT_return_error(lua_State *L);
> 
> Maybe let the name be a bit more explicit, say,
> luaT_push_conventional_error(struct lua_State *L)?
> 

Please, no. You work too much with Java. The name
is too long. Maybe luaT_push_nil_err()?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 15:40     ` Vladislav Shpilevoy
@ 2019-07-31 16:20       ` Imeev Mergen
  2019-07-31 17:00         ` Vladislav Shpilevoy
  2019-07-31 19:32         ` Konstantin Osipov
  0 siblings, 2 replies; 17+ messages in thread
From: Imeev Mergen @ 2019-07-31 16:20 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tarantool-patches, Alexander Turenko; +Cc: kostja


On 7/31/19 6:40 PM, Vladislav Shpilevoy wrote:
>
> On 31/07/2019 17:23, Alexander Turenko wrote:
>>> +/**
>>> + * Return nil as the first return value and an error as the
>>> + * second. The error is received using box_error_last().
>>> + *
>>> + * @param L Lua stack.
>>> + */
>>> +LUA_API int
>>> +luaT_return_error(lua_State *L);
>> Maybe let the name be a bit more explicit, say,
>> luaT_push_conventional_error(struct lua_State *L)?
>>
> Please, no. You work too much with Java. The name
> is too long. Maybe luaT_push_nil_err()?
I thought that luaT_error() throws an error, and this one returns
it. So I called it luaT_return_error(). Should I change the name
to luaT_push_nil_err()?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 16:20       ` Imeev Mergen
@ 2019-07-31 17:00         ` Vladislav Shpilevoy
  2019-07-31 19:33           ` Konstantin Osipov
  2019-08-01  8:35           ` Alexander Turenko
  2019-07-31 19:32         ` Konstantin Osipov
  1 sibling, 2 replies; 17+ messages in thread
From: Vladislav Shpilevoy @ 2019-07-31 17:00 UTC (permalink / raw)
  To: Imeev Mergen, tarantool-patches, Alexander Turenko; +Cc: kostja



On 31/07/2019 18:20, Imeev Mergen wrote:
> 
> On 7/31/19 6:40 PM, Vladislav Shpilevoy wrote:
>>
>> On 31/07/2019 17:23, Alexander Turenko wrote:
>>>> +/**
>>>> + * Return nil as the first return value and an error as the
>>>> + * second. The error is received using box_error_last().
>>>> + *
>>>> + * @param L Lua stack.
>>>> + */
>>>> +LUA_API int
>>>> +luaT_return_error(lua_State *L);
>>> Maybe let the name be a bit more explicit, say,
>>> luaT_push_conventional_error(struct lua_State *L)?
>>>
>> Please, no. You work too much with Java. The name
>> is too long. Maybe luaT_push_nil_err()?
> I thought that luaT_error() throws an error, and this one returns
> it. So I called it luaT_return_error(). Should I change the name
> to luaT_push_nil_err()?
> 

For me 'return' was ok, but seems it is not ok for Kostja and
Alexander. Lets wait.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error() imeevma
  2019-07-31 15:23   ` [tarantool-patches] " Alexander Turenko
@ 2019-07-31 17:15   ` Vladislav Shpilevoy
  2019-07-31 22:16     ` Mergen Imeev
  2019-08-01  8:59     ` Mergen Imeev
  1 sibling, 2 replies; 17+ messages in thread
From: Vladislav Shpilevoy @ 2019-07-31 17:15 UTC (permalink / raw)
  To: tarantool-patches, imeevma; +Cc: kostja

Hi! Thanks for the patch!

> diff --git a/src/lua/fio.c b/src/lua/fio.c
> index 55fa667..cb7e31e 100644
> --- a/src/lua/fio.c
> +++ b/src/lua/fio.c
> @@ -47,11 +47,9 @@
>  #include "lua/utils.h"
>  #include "coio_file.h"
>  
> -static inline void
> -lbox_fio_pushsyserror(struct lua_State *L)
> -{
> -	diag_set(SystemError, "fio: %s", strerror(errno));
> -	luaT_pusherror(L, diag_get()->last);
> +#define lbox_fio_pushsyserror(L) {				\
> +	diag_set(SystemError, "fio: %s", strerror(errno));	\
> +	return luaT_return_error(L);				\
>  }

Please, don't return here. It makes the code below
confusing, when you call 'pushsyserror, pushinteger', and
return 1. Make this macro return value of the last block,
and surround it with '()' or with 'do {...} while(false)'
to be force ';' after it, and be able to use it in
'if ... else ...' constructions. It is a standard practice.

#define lbox_fio_pushsyserror(L) ({				\
	diag_set(SystemError, "fio: %s", strerror(errno));	\
	luaT_return_error(L);					\
})

and use 'return lbox_fio_pushsyserror(L);' in the code
below.

>  
>  static int
> @@ -69,11 +67,8 @@ usage:
>  	int mode = lua_tointeger(L, 3);
>  
>  	int fh = coio_file_open(pathname, flags, mode);
> -	if (fh < 0) {
> -		lua_pushnil(L);
> +	if (fh < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushinteger(L, fh);
>  	return 1;
>  }
> @@ -90,11 +85,8 @@ lbox_fio_pwrite(struct lua_State *L)
>  	size_t offset = lua_tonumber(L, 4);
>  
>  	int res = coio_pwrite(fh, buf, len, offset);
> -	if (res < 0) {
> -		lua_pushnil(L);
> +	if (res < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushinteger(L, res);
>  	return 1;
>  }
> @@ -115,11 +107,8 @@ lbox_fio_pread(struct lua_State *L)
>  
>  	int res = coio_pread(fh, buf, len, offset);
>  
> -	if (res < 0) {
> -		lua_pushnil(L);
> +	if (res < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushinteger(L, res);
>  	return 1;
>  }
> @@ -129,7 +118,10 @@ lbox_fio_pushbool(struct lua_State *L, bool res)
>  {
>  	lua_pushboolean(L, res);
>  	if (!res) {
> -		lbox_fio_pushsyserror(L);
> +		diag_set(SystemError, "fio: %s", strerror(errno));
> +		struct error *e = diag_last_error(diag_get());
> +		assert(e != NULL);
> +		luaT_pusherror(L, e);
>  		return 2;
>  	}
>  	return 1;
> @@ -211,11 +203,8 @@ lbox_fio_write(struct lua_State *L)
>  	size_t len = lua_tonumber(L, 3);
>  
>  	int res = coio_write(fh, buf, len);
> -	if (res < 0) {
> -		lua_pushnil(L);
> +	if (res < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushinteger(L, res);
>  	return 1;
>  }
> @@ -298,11 +287,8 @@ lbox_fio_read(struct lua_State *L)
>  
>  	int res = coio_read(fh, buf, len);
>  
> -	if (res < 0) {
> -		lua_pushnil(L);
> +	if (res < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushinteger(L, res);
>  	return 1;
>  }
> @@ -371,11 +357,8 @@ DEF_STAT_METHOD(is_sock, S_ISSOCK);
>  static int
>  lbox_fio_pushstat(struct lua_State *L, int res, const struct stat *stat)
>  {
> -	if (res < 0) {
> -		lua_pushnil(L);
> +	if (res < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_newtable(L);
>  
>  	PUSHTABLE("dev", lua_pushinteger, stat->st_dev);
> @@ -518,11 +501,8 @@ lbox_fio_listdir(struct lua_State *L)
>  	}
>  	pathname = lua_tostring(L, 1);
>  	char *buf;
> -	if (coio_readdir(pathname, &buf) < 0) {
> -		lua_pushnil(L);
> +	if (coio_readdir(pathname, &buf) < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushstring(L, buf);
>  	free(buf);
>  	return 1;
> @@ -613,11 +593,8 @@ usage:
>  		goto usage;
>  	char *path = (char *)lua_newuserdata(L, PATH_MAX);
>  	int res = coio_readlink(pathname, path, PATH_MAX);
> -	if (res < 0) {
> -		lua_pushnil(L);
> +	if (res < 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushlstring(L, path, res);
>  	lua_remove(L, -2);
>  	return 1;
> @@ -629,16 +606,11 @@ lbox_fio_tempdir(struct lua_State *L)
>  	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
>  	if (!buf) {
>  		errno = ENOMEM;
> -		lua_pushnil(L);
>  		lbox_fio_pushsyserror(L);
> -		return 2;
>  	}
>  
> -	if (coio_tempdir(buf, PATH_MAX) != 0) {
> -		lua_pushnil(L);
> +	if (coio_tempdir(buf, PATH_MAX) != 0)
>  		lbox_fio_pushsyserror(L);
> -		return 2;
> -	}
>  	lua_pushstring(L, buf);
>  	lua_remove(L, -2);
>  	return 1;
> @@ -650,20 +622,12 @@ lbox_fio_cwd(struct lua_State *L)
>  	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
>  	if (!buf) {
>  		errno = ENOMEM;
> -		lua_pushnil(L);
>  		lbox_fio_pushsyserror(L);
> -		return 2;
>  	}
> -
> -
> -	if (getcwd(buf, PATH_MAX)) {
> -		lua_pushstring(L, buf);
> -		lua_remove(L, -2);
> -	} else {
> +	if (getcwd(buf, PATH_MAX) == NULL)
>  		lbox_fio_pushsyserror(L);
> -		lua_pushnil(L);
> -		return 2;
> -	}
> +	lua_pushstring(L, buf);
> +	lua_remove(L, -2);
>  	return 1;
>  }

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 16:20       ` Imeev Mergen
  2019-07-31 17:00         ` Vladislav Shpilevoy
@ 2019-07-31 19:32         ` Konstantin Osipov
  1 sibling, 0 replies; 17+ messages in thread
From: Konstantin Osipov @ 2019-07-31 19:32 UTC (permalink / raw)
  To: Imeev Mergen; +Cc: Vladislav Shpilevoy, tarantool-patches, Alexander Turenko

> to luaT_push_nil_err()?

luaT_push_nil_and_error then

-- 
Konstantin Osipov, Moscow, Russia

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 17:00         ` Vladislav Shpilevoy
@ 2019-07-31 19:33           ` Konstantin Osipov
  2019-08-01  8:35           ` Alexander Turenko
  1 sibling, 0 replies; 17+ messages in thread
From: Konstantin Osipov @ 2019-07-31 19:33 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: Imeev Mergen, tarantool-patches, Alexander Turenko

* Vladislav Shpilevoy <v.shpilevoy@tarantool.org> [19/07/31 20:01]:
> >>>> +LUA_API int
> >>>> +luaT_return_error(lua_State *L);
> For me 'return' was ok, but seems it is not ok for Kostja and
> Alexander. Lets wait.

I'm OK with it. luaT_return_nil_and_error is also OK.
luaT_push_nil_and_error too.

luaT_return_error is a bit ambiguous, and like names which are
self-explanatory, but it's fine.

-- 
Konstantin Osipov, Moscow, Russia

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 17:15   ` Vladislav Shpilevoy
@ 2019-07-31 22:16     ` Mergen Imeev
  2019-08-01 20:03       ` Vladislav Shpilevoy
  2019-08-01  8:59     ` Mergen Imeev
  1 sibling, 1 reply; 17+ messages in thread
From: Mergen Imeev @ 2019-07-31 22:16 UTC (permalink / raw)
  To: tarantool-patches; +Cc: kostja

Hi! Thank you for review. I made changes you mentioned and
renamed function to luaT_push_nil_and_error().

Also, I noted that in function lbox_fio_cwd() before this
patch something was not right. Diff:

@@ -650,20 +622,12 @@ lbox_fio_cwd(struct lua_State *L)
        char *buf = (char *)lua_newuserdata(L, PATH_MAX);
        if (!buf) {
                errno = ENOMEM;
-               lua_pushnil(L);
-               lbox_fio_pushsyserror(L);
-               return 2;
-       }
-
-
-       if (getcwd(buf, PATH_MAX)) {
-               lua_pushstring(L, buf);
-               lua_remove(L, -2);
-       } else {
-               lbox_fio_pushsyserror(L);
-               lua_pushnil(L);
-               return 2;
+               return lbox_fio_pushsyserror(L);
        }
+       if (getcwd(buf, PATH_MAX) == NULL)
+               return lbox_fio_pushsyserror(L);
+       lua_pushstring(L, buf);
+       lua_remove(L, -2);
        return 1;
 }

As you can see, in the first case nil was the first and
error was the second, but it wasn't so in the other case.
I think this was a bug.

My answer and new patch below.

On Wed, Jul 31, 2019 at 07:15:13PM +0200, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patch!
> 
> > diff --git a/src/lua/fio.c b/src/lua/fio.c
> > index 55fa667..cb7e31e 100644
> > --- a/src/lua/fio.c
> > +++ b/src/lua/fio.c
> > @@ -47,11 +47,9 @@
> >  #include "lua/utils.h"
> >  #include "coio_file.h"
> >  
> > -static inline void
> > -lbox_fio_pushsyserror(struct lua_State *L)
> > -{
> > -	diag_set(SystemError, "fio: %s", strerror(errno));
> > -	luaT_pusherror(L, diag_get()->last);
> > +#define lbox_fio_pushsyserror(L) {				\
> > +	diag_set(SystemError, "fio: %s", strerror(errno));	\
> > +	return luaT_return_error(L);				\
> >  }
> 
> Please, don't return here. It makes the code below
> confusing, when you call 'pushsyserror, pushinteger', and
> return 1. Make this macro return value of the last block,
> and surround it with '()' or with 'do {...} while(false)'
> to be force ';' after it, and be able to use it in
> 'if ... else ...' constructions. It is a standard practice.
> 
> #define lbox_fio_pushsyserror(L) ({				\
> 	diag_set(SystemError, "fio: %s", strerror(errno));	\
> 	luaT_return_error(L);					\
> })
> 
> and use 'return lbox_fio_pushsyserror(L);' in the code
> below.
> 
Thank you! Fixed.


New patch:

From 06f6a8f4e103e759233823ea508f9764a371f026 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Wed, 31 Jul 2019 12:43:58 +0300
Subject: [PATCH] lua: new function luaT_push_nil_and_error()

Currently, if we have to return errors using the format
'return nil, error', we must do it manually. Since this error
return method is described in our Lua coding style, it makes sense
to create a function that will return an error in this format.
This patch creates mentioned function.

Needed for #4390

diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index c0ac4917b..b9495e7a6 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -395,14 +395,10 @@ lbox_session_push(struct lua_State *L)
 	}
 	struct port port;
 	port_lua_create(&port, L);
-	if (session_push(session, sync, &port) != 0) {
-		lua_pushnil(L);
-		luaT_pusherror(L, box_error_last());
-		return 2;
-	} else {
-		lua_pushboolean(L, true);
-		return 1;
-	}
+	if (session_push(session, sync, &port) != 0)
+		return luaT_push_nil_and_error(L);
+	lua_pushboolean(L, true);
+	return 1;
 }
 
 /**
diff --git a/src/lua/error.c b/src/lua/error.c
index fca87f9d6..d82e78dc4 100644
--- a/src/lua/error.c
+++ b/src/lua/error.c
@@ -104,6 +104,16 @@ luaT_error(lua_State *L)
 	return 0;
 }
 
+int
+luaT_push_nil_and_error(lua_State *L)
+{
+	struct error *e = diag_last_error(&fiber()->diag);
+	assert(e != NULL);
+	lua_pushnil(L);
+	luaT_pusherror(L, e);
+	return 2;
+}
+
 void
 tarantool_lua_error_init(struct lua_State *L)
 {
diff --git a/src/lua/error.h b/src/lua/error.h
index 67a43da86..64fa5eba3 100644
--- a/src/lua/error.h
+++ b/src/lua/error.h
@@ -49,6 +49,15 @@ struct error;
 LUA_API int
 luaT_error(lua_State *L);
 
+/**
+ * Return nil as the first return value and an error as the
+ * second. The error is received using box_error_last().
+ *
+ * @param L Lua stack.
+ */
+LUA_API int
+luaT_push_nil_and_error(lua_State *L);
+
 void
 luaT_pusherror(struct lua_State *L, struct error *e);
 /** \endcond public */
diff --git a/src/lua/fio.c b/src/lua/fio.c
index 55fa66762..e5d3458fd 100644
--- a/src/lua/fio.c
+++ b/src/lua/fio.c
@@ -47,12 +47,10 @@
 #include "lua/utils.h"
 #include "coio_file.h"
 
-static inline void
-lbox_fio_pushsyserror(struct lua_State *L)
-{
-	diag_set(SystemError, "fio: %s", strerror(errno));
-	luaT_pusherror(L, diag_get()->last);
-}
+#define lbox_fio_pushsyserror(L) ({				\
+	diag_set(SystemError, "fio: %s", strerror(errno));	\
+	luaT_push_nil_and_error(L);					\
+})
 
 static int
 lbox_fio_open(struct lua_State *L)
@@ -69,11 +67,8 @@ usage:
 	int mode = lua_tointeger(L, 3);
 
 	int fh = coio_file_open(pathname, flags, mode);
-	if (fh < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (fh < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, fh);
 	return 1;
 }
@@ -90,11 +85,8 @@ lbox_fio_pwrite(struct lua_State *L)
 	size_t offset = lua_tonumber(L, 4);
 
 	int res = coio_pwrite(fh, buf, len, offset);
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -115,11 +107,8 @@ lbox_fio_pread(struct lua_State *L)
 
 	int res = coio_pread(fh, buf, len, offset);
 
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -129,7 +118,10 @@ lbox_fio_pushbool(struct lua_State *L, bool res)
 {
 	lua_pushboolean(L, res);
 	if (!res) {
-		lbox_fio_pushsyserror(L);
+		diag_set(SystemError, "fio: %s", strerror(errno));
+		struct error *e = diag_last_error(diag_get());
+		assert(e != NULL);
+		luaT_pusherror(L, e);
 		return 2;
 	}
 	return 1;
@@ -211,11 +203,8 @@ lbox_fio_write(struct lua_State *L)
 	size_t len = lua_tonumber(L, 3);
 
 	int res = coio_write(fh, buf, len);
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -298,11 +287,8 @@ lbox_fio_read(struct lua_State *L)
 
 	int res = coio_read(fh, buf, len);
 
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -371,11 +357,8 @@ DEF_STAT_METHOD(is_sock, S_ISSOCK);
 static int
 lbox_fio_pushstat(struct lua_State *L, int res, const struct stat *stat)
 {
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_newtable(L);
 
 	PUSHTABLE("dev", lua_pushinteger, stat->st_dev);
@@ -518,11 +501,8 @@ lbox_fio_listdir(struct lua_State *L)
 	}
 	pathname = lua_tostring(L, 1);
 	char *buf;
-	if (coio_readdir(pathname, &buf) < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (coio_readdir(pathname, &buf) < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushstring(L, buf);
 	free(buf);
 	return 1;
@@ -613,11 +593,8 @@ usage:
 		goto usage;
 	char *path = (char *)lua_newuserdata(L, PATH_MAX);
 	int res = coio_readlink(pathname, path, PATH_MAX);
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushlstring(L, path, res);
 	lua_remove(L, -2);
 	return 1;
@@ -629,16 +606,11 @@ lbox_fio_tempdir(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
+		return lbox_fio_pushsyserror(L);
 	}
 
-	if (coio_tempdir(buf, PATH_MAX) != 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (coio_tempdir(buf, PATH_MAX) != 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushstring(L, buf);
 	lua_remove(L, -2);
 	return 1;
@@ -650,20 +622,12 @@ lbox_fio_cwd(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
-
-
-	if (getcwd(buf, PATH_MAX)) {
-		lua_pushstring(L, buf);
-		lua_remove(L, -2);
-	} else {
-		lbox_fio_pushsyserror(L);
-		lua_pushnil(L);
-		return 2;
+		return lbox_fio_pushsyserror(L);
 	}
+	if (getcwd(buf, PATH_MAX) == NULL)
+		return lbox_fio_pushsyserror(L);
+	lua_pushstring(L, buf);
+	lua_remove(L, -2);
 	return 1;
 }
 
diff --git a/src/lua/swim.c b/src/lua/swim.c
index 26646f41f..ae916bf78 100644
--- a/src/lua/swim.c
+++ b/src/lua/swim.c
@@ -69,11 +69,10 @@ lua_swim_new(struct lua_State *L)
 {
 	uint64_t generation = luaL_checkuint64(L, 1);
 	struct swim *s = swim_new(generation);
+	if (s == NULL)
+		return luaT_push_nil_and_error(L);
 	*(struct swim **) luaL_pushcdata(L, ctid_swim_ptr) = s;
-	if (s != NULL)
-		return 1;
-	luaT_pusherror(L, diag_last_error(diag_get()));
-	return 2;
+	return 1;
 }
 
 /**

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 2/2] sql: rework error handling in box.execute()
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 2/2] sql: rework error handling in box.execute() imeevma
@ 2019-07-31 22:23   ` Mergen Imeev
  0 siblings, 0 replies; 17+ messages in thread
From: Mergen Imeev @ 2019-07-31 22:23 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: kostja, tarantool-patches

After rebase changes in test sql/ddl.test.lua were added and
some changes in test sql/errinj.test.lua were removed.

New patch:

From cfeabc36b0451c48845650e8683110b54bedb568 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Tue, 30 Jul 2019 15:50:29 +0300
Subject: [PATCH] sql: rework error handling in box.execute()

In accordance with the Lua coding style in Tarantool, all errors
returned in Lua should be returned using 'return nil, error'.
However, box.execute() throws an exception in case of an error.
This patch causes box.execute() to return an error, as described
in the coding style.

Closes #4390

diff --git a/src/box/lua/execute.c b/src/box/lua/execute.c
index 7b7c57529..76ecdd541 100644
--- a/src/box/lua/execute.c
+++ b/src/box/lua/execute.c
@@ -255,12 +255,12 @@ lbox_execute(struct lua_State *L)
 			return luaL_error(L, "Second argument must be a table");
 		bind_count = lua_sql_bind_list_decode(L, &bind, 2);
 		if (bind_count < 0)
-			return luaT_error(L);
+			return luaT_push_nil_and_error(L);
 	}
 
 	if (sql_prepare_and_execute(sql, length, bind, bind_count, &port,
 				    &fiber()->gc) != 0)
-		return luaT_error(L);
+		return luaT_push_nil_and_error(L);
 	port_dump_lua(&port, L, false);
 	port_destroy(&port);
 	return 1;
diff --git a/test/sql-tap/gh2548-select-compound-limit.test.lua b/test/sql-tap/gh2548-select-compound-limit.test.lua
index 9589a3730..f5788701a 100755
--- a/test/sql-tap/gh2548-select-compound-limit.test.lua
+++ b/test/sql-tap/gh2548-select-compound-limit.test.lua
@@ -14,30 +14,30 @@ for _, term in ipairs({'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT'}) do
                  function()
                      for i = 1,table_count do
                          drop_string = 'DROP TABLE IF EXISTS t' .. i .. ';\n'
-                         box.execute(drop_string)
+                         test:execsql(drop_string)
                      end
 
                      for i = 1,table_count do
                          create_string = 'CREATE TABLE t' .. i .. ' (s1 int primary key, s2 int);\n'
-                         box.execute(create_string)
+                         test:execsql(create_string)
                      end
 
                      for i = 1,table_count do
                          insert_string = 'INSERT INTO t' .. i .. ' VALUES (0,' .. i .. ');\n'
-                         box.execute(insert_string)
+                         test:execsql(insert_string)
                      end
 
                      for i = 1,table_count-1 do
                          if i > 1 then select_string = select_string .. ' ' .. term .. ' ' end
                          select_string = select_string .. 'SELECT * FROM t' .. i
                      end
-                     return pcall( function() box.execute(select_string) end)
+                     return pcall( function() test:execsql(select_string) end)
                  end,
                  true)
     test:do_test("Negative COMPOUND "..term,
                  function()
                      select_string = select_string .. ' ' .. term ..' ' .. 'SELECT * FROM t' .. table_count
-                     return  pcall(function() box.execute(select_string) end)
+                     return  pcall(function() test:execsql(select_string) end)
                  end,
                  false)
 
diff --git a/test/sql-tap/lua/sqltester.lua b/test/sql-tap/lua/sqltester.lua
index e83a8e404..0f3411419 100644
--- a/test/sql-tap/lua/sqltester.lua
+++ b/test/sql-tap/lua/sqltester.lua
@@ -150,7 +150,10 @@ local function execsql_one_by_one(sql)
     local last_res_rows = nil
     local last_res_metadata = nil
     for _, query in pairs(queries) do
-        local new_res = box.execute(query)
+        local new_res, err = box.execute(query)
+        if err ~= nil then
+            error(err)
+        end
         if new_res ~= nil and new_res.rows ~= nil then
             last_res_rows = new_res.rows
             last_res_metadata = new_res.metadata
diff --git a/test/sql/bind.result b/test/sql/bind.result
index cd0fcc0b1..1e02620cb 100644
--- a/test/sql/bind.result
+++ b/test/sql/bind.result
@@ -36,7 +36,13 @@ if remote then
 	cn = netbox.connect(box.cfg.listen)
 	execute = function(...) return cn:execute(...) end
 else
-	execute = box.execute
+	execute = function(...)
+		local res, err = box.execute(...)
+		if err ~= nil then
+			error(err)
+		end
+		return res
+	end
 end;
 ---
 ...
@@ -310,9 +316,11 @@ box.execute('DROP TABLE test')
 ...
 box.execute('SELECT ?', {1, 2})
 ---
-- error: 'Failed to execute SQL statement: The number of parameters is too large'
+- null
+- 'Failed to execute SQL statement: The number of parameters is too large'
 ...
 box.execute('SELECT $2', {1, 2, 3})
 ---
-- error: 'Failed to execute SQL statement: The number of parameters is too large'
+- null
+- 'Failed to execute SQL statement: The number of parameters is too large'
 ...
diff --git a/test/sql/bind.test.lua b/test/sql/bind.test.lua
index f311a0a71..2b41af7e0 100644
--- a/test/sql/bind.test.lua
+++ b/test/sql/bind.test.lua
@@ -15,7 +15,13 @@ if remote then
 	cn = netbox.connect(box.cfg.listen)
 	execute = function(...) return cn:execute(...) end
 else
-	execute = box.execute
+	execute = function(...)
+		local res, err = box.execute(...)
+		if err ~= nil then
+			error(err)
+		end
+		return res
+	end
 end;
 test_run:cmd("setopt delimiter ''");
 --
diff --git a/test/sql/checks.result b/test/sql/checks.result
index b20514993..f919862ab 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -73,7 +73,8 @@ box.space._ck_constraint:count({})
 ...
 box.execute("INSERT INTO \"test\" VALUES(5);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
 ...
 box.space.test:insert({5})
 ---
@@ -89,7 +90,8 @@ box.execute("INSERT INTO \"test\" VALUES(5);")
 ...
 box.execute("INSERT INTO \"test\" VALUES(6);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
 ...
 box.space.test:insert({6})
 ---
@@ -126,7 +128,8 @@ box.space._ck_constraint:count()
 ...
 box.execute("INSERT INTO t1 VALUES (7, 1, 1)")
 ---
-- error: 'Check constraint failed ''ONE'': x<5'
+- null
+- 'Check constraint failed ''ONE'': x<5'
 ...
 box.space.T1:insert({7, 1, 1})
 ---
@@ -134,7 +137,8 @@ box.space.T1:insert({7, 1, 1})
 ...
 box.execute("INSERT INTO t1 VALUES (2, 1, 1)")
 ---
-- error: 'Check constraint failed ''TWO'': y>x'
+- null
+- 'Check constraint failed ''TWO'': y>x'
 ...
 box.space.T1:insert({2, 1, 1})
 ---
@@ -155,7 +159,8 @@ box.execute("DROP TABLE t1")
 -- Test space creation rollback on spell error in ck constraint.
 box.execute("CREATE TABLE first (id NUMBER PRIMARY KEY CHECK(id < 5), a INT CONSTRAINT ONE CHECK(a >< 5));")
 ---
-- error: Syntax error near '<'
+- null
+- Syntax error near '<'
 ...
 box.space.FIRST == nil
 ---
@@ -184,14 +189,16 @@ _ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y'})
 ...
 box.execute("INSERT INTO \"test\" VALUES(2, 1);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 s:format({{name='Y', type='integer'}, {name='X', type='integer'}})
 ---
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(2, 1);")
 ---
@@ -202,7 +209,8 @@ s:truncate()
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 s:format({})
 ---
@@ -234,11 +242,13 @@ _ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'})
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''conflict'': X>10'
+- null
+- 'Check constraint failed ''conflict'': X>10'
 ...
 box.execute("INSERT INTO \"test\" VALUES(11, 11);")
 ---
-- error: 'Check constraint failed ''physics'': X<Y'
+- null
+- 'Check constraint failed ''physics'': X<Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(12, 11);")
 ---
@@ -249,7 +259,8 @@ s:drop()
 ...
 box.execute("CREATE TABLE T2(ID INT PRIMARY KEY, CONSTRAINT CK1 CHECK(ID > 0), CONSTRAINT CK1 CHECK(ID < 0))")
 ---
-- error: Constraint CK1 already exists
+- null
+- Constraint CK1 already exists
 ...
 box.space.T2
 ---
@@ -264,20 +275,23 @@ box.space._ck_constraint:select()
 --
 box.execute("CREATE TABLE w2 (s1 INT PRIMARY KEY, CHECK ((SELECT COUNT(*) FROM w2) = 0));")
 ---
-- error: 'Failed to create check constraint ''CK_CONSTRAINT_1_W2'': Subqueries are
-    prohibited in a ck constraint definition'
+- null
+- 'Failed to create check constraint ''CK_CONSTRAINT_1_W2'': Subqueries are prohibited
+  in a ck constraint definition'
 ...
 box.execute("DROP TABLE w2;")
 ---
-- error: Space 'W2' does not exist
+- null
+- Space 'W2' does not exist
 ...
 --
 -- gh-3653: Dissallow bindings for DDL
 --
 box.execute("CREATE TABLE t5(x INT PRIMARY KEY, y INT, CHECK( x*y < ? ));")
 ---
-- error: 'Failed to create check constraint ''CK_CONSTRAINT_1_T5'': bindings are not
-    allowed in DDL'
+- null
+- 'Failed to create check constraint ''CK_CONSTRAINT_1_T5'': bindings are not allowed
+  in DDL'
 ...
 -- Test trim CK constraint code correctness.
 box.execute("CREATE TABLE t1(x TEXT PRIMARY KEY CHECK(x    LIKE     '1  a'))")
@@ -290,11 +304,13 @@ box.space._ck_constraint:select()[1].code
 ...
 box.execute("INSERT INTO t1 VALUES('1 a')")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
 ...
 box.execute("INSERT INTO t1 VALUES('1   a')")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': x LIKE ''1  a'''
 ...
 box.execute("INSERT INTO t1 VALUES('1  a')")
 ---
diff --git a/test/sql/clear.result b/test/sql/clear.result
index 2fb17615c..afa6520e8 100644
--- a/test/sql/clear.result
+++ b/test/sql/clear.result
@@ -176,7 +176,8 @@ box.execute("DROP TABLE zoobar")
 --
 box.execute("CREATE TABLE t1(id INT PRIMARY KEY, CONSTRAINT ck1 CHECK(id > 0), CONSTRAINT ck1 CHECK(id < 0));")
 ---
-- error: Constraint CK1 already exists
+- null
+- Constraint CK1 already exists
 ...
 box.space.t1
 ---
@@ -188,7 +189,8 @@ box.space._ck_constraint:select()
 ...
 box.execute("CREATE TABLE t2(id INT PRIMARY KEY, CONSTRAINT fk1 FOREIGN KEY(id) REFERENCES t2, CONSTRAINT fk1 FOREIGN KEY(id) REFERENCES t2);")
 ---
-- error: Constraint FK1 already exists
+- null
+- Constraint FK1 already exists
 ...
 box.space.t2
 ---
@@ -204,7 +206,8 @@ box.space._fk_constraint:select()
 --
 box.execute("CREATE TABLE t3(id INT PRIMARY KEY, CONSTRAINT ck1 CHECK(id > 0), CONSTRAINT ck1 FOREIGN KEY(id) REFERENCES t3, CONSTRAINT fk1 FOREIGN KEY(id) REFERENCES t3, CONSTRAINT ck1 CHECK(id < 0));")
 ---
-- error: Constraint CK1 already exists
+- null
+- Constraint CK1 already exists
 ...
 box.space.t1
 ---
diff --git a/test/sql/collation.result b/test/sql/collation.result
index 436ce3256..11962ef47 100644
--- a/test/sql/collation.result
+++ b/test/sql/collation.result
@@ -15,23 +15,28 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 -- All of these tests should throw error "near "COLLATE": syntax error"
 box.execute("SELECT 1 LIMIT 1 COLLATE BINARY;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1 COLLATE BINARY OFFSET 1;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1 OFFSET 1 COLLATE BINARY;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1, 1 COLLATE BINARY;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 box.execute("SELECT 1 LIMIT 1 COLLATE BINARY, 1;")
 ---
-- error: Syntax error near 'COLLATE'
+- null
+- Syntax error near 'COLLATE'
 ...
 -- gh-3052: upper/lower support only default locale
 -- For tr-TR result depends on collation
@@ -253,7 +258,8 @@ box.execute("SELECT * FROM t WHERE a COLLATE \"binary\" = b;")
 ...
 box.execute("SELECT * FROM t WHERE b = c;")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT * FROM t WHERE b COLLATE \"binary\" = c;")
 ---
@@ -283,22 +289,26 @@ box.execute("SELECT * FROM t WHERE a = c;")
 ...
 box.execute("SELECT * FROM t WHERE a COLLATE \"binary\" = c COLLATE \"unicode\";")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 -- Compound queries perform implicit comparisons between values.
 -- Hence, rules for collations compatibilities are the same.
 --
 box.execute("SELECT 'abc' COLLATE \"binary\" UNION SELECT 'ABC' COLLATE \"unicode_ci\"")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT 'abc' COLLATE \"unicode_ci\" UNION SELECT 'ABC' COLLATE binary")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT c FROM t UNION SELECT b FROM t;")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT b FROM t UNION SELECT a FROM t;")
 ---
@@ -345,7 +355,8 @@ box.session.su('tmp')
 -- Error: read access to space is denied.
 box.execute("pragma collation_list")
 ---
-- error: Read access to space '_collation' is denied for user 'tmp'
+- null
+- Read access to space '_collation' is denied for user 'tmp'
 ...
 box.session.su('admin')
 ---
@@ -426,7 +437,8 @@ box.execute("INSERT INTO t1 VALUES (1,'a');")
 -- Should fail.
 box.execute("UPDATE t0 SET s1 = 'A';")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.execute("SELECT * FROM t1;")
 ---
@@ -496,11 +508,13 @@ box.execute("SELECT c FROM t4a WHERE (a COLLATE \"binary\"||'') = b;")
 --
 box.execute("SELECT c FROM t4a WHERE (a COLLATE \"binary\"||'' COLLATE \"unicode_ci\") = b;")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("SELECT c FROM t4a WHERE (a COLLATE \"binary\"||'') = b COLLATE \"unicode\";")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 -- No collation is used since LHS and RHS of concatenation
 -- operator have different implicit collations.
@@ -555,7 +569,8 @@ box.execute("SELECT c FROM t4a WHERE (a||b COLLATE \"binary\")=(b||a);")
 ...
 box.execute("SELECT c FROM t4a WHERE (a||b COLLATE \"binary\")=(b COLLATE \"unicode_ci\"||a);")
 ---
-- error: Illegal mix of collations
+- null
+- Illegal mix of collations
 ...
 box.execute("INSERT INTO t4b VALUES('abc', 'xxx', 2);")
 ---
@@ -676,7 +691,8 @@ box.execute("INSERT INTO t3b VALUES ('A');")
 ...
 box.execute("INSERT INTO t3b VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3B_1' in space 'T3B'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3B_1' in space 'T3B'
 ...
 box.execute("SELECT * FROM t3b;")
 ---
@@ -740,7 +756,8 @@ box.execute("INSERT INTO t3c VALUES ('A');")
 ...
 box.execute("INSERT INTO t3c VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3C_1' in space 'T3C'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3C_1' in space 'T3C'
 ...
 box.execute("SELECT * FROM t3c;")
 ---
@@ -804,7 +821,8 @@ box.execute("INSERT INTO t3d VALUES ('A');")
 ...
 box.execute("INSERT INTO t3d VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3D_1' in space 'T3D'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3D_1' in space 'T3D'
 ...
 box.execute("SELECT * FROM t3d;")
 ---
@@ -834,7 +852,8 @@ box.execute("INSERT INTO t3e VALUES ('a');")
 ...
 box.execute("INSERT INTO t3e VALUES ('A');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3E_1' in space 'T3E'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3E_1' in space 'T3E'
 ...
 box.execute("SELECT * FROM t3e;")
 ---
@@ -897,7 +916,8 @@ box.execute("INSERT INTO t3f VALUES ('A');")
 ...
 box.execute("INSERT INTO t3f VALUES ('a');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3F_1' in space 'T3F'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3F_1' in space 'T3F'
 ...
 box.execute("SELECT * FROM t3f;")
 ---
@@ -927,7 +947,8 @@ box.execute("INSERT INTO t3g VALUES ('a');")
 ...
 box.execute("INSERT INTO t3g VALUES ('A');")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_T3G_1' in space 'T3G'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_T3G_1' in space 'T3G'
 ...
 box.execute("SELECT * FROM t3g;")
 ---
diff --git a/test/sql/ddl.result b/test/sql/ddl.result
index a47e15bb4..28acf37ea 100644
--- a/test/sql/ddl.result
+++ b/test/sql/ddl.result
@@ -104,10 +104,10 @@ test_run:cmd("setopt delimiter ';'")
  | ---
  | - true
  | ...
-box.begin()
-box.execute('CREATE TABLE t2(id INTEGER PRIMARY KEY)')
-box.execute('CREATE INDEX t1a ON t1(a)')
-box.execute('CREATE INDEX t1b ON t1(b)')
+box.begin(),
+box.execute('CREATE TABLE t2(id INTEGER PRIMARY KEY)') or box.error(),
+box.execute('CREATE INDEX t1a ON t1(a)') or box.error(),
+box.execute('CREATE INDEX t1b ON t1(b)') or box.error(),
 box.commit();
  | ---
  | - error: Can not perform index build in a multi-statement transaction
@@ -277,7 +277,7 @@ function monster_ddl()
 
     box.execute('ALTER TABLE t1 ADD CONSTRAINT ck1 CHECK(b > 0);')
 
-    _, err1 = pcall(box.execute, 'ALTER TABLE t_to_rename RENAME TO t1;')
+    _, err1 = box.execute('ALTER TABLE t_to_rename RENAME TO t1;')
 
     box.execute('ALTER TABLE t1 ADD CONSTRAINT ck2 CHECK(a > 0);')
     box.space.T1.ck_constraint.CK1:drop()
@@ -286,7 +286,7 @@ function monster_ddl()
                   (a) REFERENCES t2(b);]])
     box.execute('ALTER TABLE t1 DROP CONSTRAINT fk1;')
 
-    _, err2 = pcall(box.execute, 'CREATE TABLE t1(id INTEGER PRIMARY KEY);')
+    _, err2 = box.execute('CREATE TABLE t1(id INTEGER PRIMARY KEY);')
 
     box.execute([[ALTER TABLE t1 ADD CONSTRAINT fk1 FOREIGN KEY
                   (a) REFERENCES t2(b);]])
@@ -303,18 +303,18 @@ function monster_ddl()
                       INSERT INTO trigger_catcher VALUES(1);
                   END; ]])
 
-    _, err3 = pcall(box.execute, 'DROP TABLE t3;')
+    _, err3 = box.execute('DROP TABLE t3;')
 
     box.execute([[CREATE TRIGGER t2t AFTER INSERT ON t2 FOR EACH ROW
                   BEGIN
                       INSERT INTO trigger_catcher VALUES(1);
                   END; ]])
 
-    _, err4 = pcall(box.execute, 'CREATE INDEX t1a ON t1(a, b);')
+    _, err4 = box.execute('CREATE INDEX t1a ON t1(a, b);')
 
     box.execute('TRUNCATE TABLE t1;')
-    _, err5 = pcall(box.execute, 'TRUNCATE TABLE t2;')
-    _, err6 = pcall(box.execute, 'TRUNCATE TABLE t_does_not_exist;')
+    _, err5 = box.execute('TRUNCATE TABLE t2;')
+    _, err6 = box.execute('TRUNCATE TABLE t_does_not_exist;')
 
     box.execute('DROP TRIGGER t2t;')
 
@@ -344,11 +344,11 @@ end$
  | ...
 function monster_ddl_check()
     local _, err1, err2, err3, err4, res
-    _, err1 = pcall(box.execute, 'INSERT INTO t2 VALUES (1, 1, 101)')
+    _, err1 = box.execute('INSERT INTO t2 VALUES (1, 1, 101)')
     box.execute('INSERT INTO t2 VALUES (1, 1, 1)')
-    _, err2 = pcall(box.execute, 'INSERT INTO t2 VALUES(2, 2, 1)')
-    _, err3 = pcall(box.execute, 'INSERT INTO t1 VALUES(1, 20, 1)')
-    _, err4 = pcall(box.execute, 'INSERT INTO t1 VALUES(1, -1, 1)')
+    _, err2 = box.execute('INSERT INTO t2 VALUES(2, 2, 1)')
+    _, err3 = box.execute('INSERT INTO t1 VALUES(1, 20, 1)')
+    _, err4 = box.execute('INSERT INTO t1 VALUES(1, -1, 1)')
     box.execute('INSERT INTO t1 VALUES (1, 1, 1)')
     res = box.execute('SELECT * FROM trigger_catcher')
     assert(box.space.T_RENAMED ~= nil)
@@ -362,7 +362,7 @@ end$
 function monster_ddl_clear()
     box.execute('DROP TRIGGER IF EXISTS t1t;')
     box.execute('DROP TABLE IF EXISTS trigger_catcher;')
-    pcall(box.execute, 'ALTER TABLE t1 DROP CONSTRAINT fk1;')
+    box.execute('ALTER TABLE t1 DROP CONSTRAINT fk1;')
     box.execute('DROP TABLE IF EXISTS t2')
     box.execute('DROP TABLE IF EXISTS t1')
     box.execute('DROP TABLE IF EXISTS t_renamed')
diff --git a/test/sql/ddl.test.lua b/test/sql/ddl.test.lua
index 371f0339e..6067b6192 100644
--- a/test/sql/ddl.test.lua
+++ b/test/sql/ddl.test.lua
@@ -42,10 +42,10 @@ box.space.T1:replace{5, 5, 5}
 box.snapshot()
 
 test_run:cmd("setopt delimiter ';'")
-box.begin()
-box.execute('CREATE TABLE t2(id INTEGER PRIMARY KEY)')
-box.execute('CREATE INDEX t1a ON t1(a)')
-box.execute('CREATE INDEX t1b ON t1(b)')
+box.begin(),
+box.execute('CREATE TABLE t2(id INTEGER PRIMARY KEY)') or box.error(),
+box.execute('CREATE INDEX t1a ON t1(a)') or box.error(),
+box.execute('CREATE INDEX t1b ON t1(b)') or box.error(),
 box.commit();
 test_run:cmd("setopt delimiter ''");
 box.rollback()
@@ -140,7 +140,7 @@ function monster_ddl()
 
     box.execute('ALTER TABLE t1 ADD CONSTRAINT ck1 CHECK(b > 0);')
 
-    _, err1 = pcall(box.execute, 'ALTER TABLE t_to_rename RENAME TO t1;')
+    _, err1 = box.execute('ALTER TABLE t_to_rename RENAME TO t1;')
 
     box.execute('ALTER TABLE t1 ADD CONSTRAINT ck2 CHECK(a > 0);')
     box.space.T1.ck_constraint.CK1:drop()
@@ -149,7 +149,7 @@ function monster_ddl()
                   (a) REFERENCES t2(b);]])
     box.execute('ALTER TABLE t1 DROP CONSTRAINT fk1;')
 
-    _, err2 = pcall(box.execute, 'CREATE TABLE t1(id INTEGER PRIMARY KEY);')
+    _, err2 = box.execute('CREATE TABLE t1(id INTEGER PRIMARY KEY);')
 
     box.execute([[ALTER TABLE t1 ADD CONSTRAINT fk1 FOREIGN KEY
                   (a) REFERENCES t2(b);]])
@@ -166,18 +166,18 @@ function monster_ddl()
                       INSERT INTO trigger_catcher VALUES(1);
                   END; ]])
 
-    _, err3 = pcall(box.execute, 'DROP TABLE t3;')
+    _, err3 = box.execute('DROP TABLE t3;')
 
     box.execute([[CREATE TRIGGER t2t AFTER INSERT ON t2 FOR EACH ROW
                   BEGIN
                       INSERT INTO trigger_catcher VALUES(1);
                   END; ]])
 
-    _, err4 = pcall(box.execute, 'CREATE INDEX t1a ON t1(a, b);')
+    _, err4 = box.execute('CREATE INDEX t1a ON t1(a, b);')
 
     box.execute('TRUNCATE TABLE t1;')
-    _, err5 = pcall(box.execute, 'TRUNCATE TABLE t2;')
-    _, err6 = pcall(box.execute, 'TRUNCATE TABLE t_does_not_exist;')
+    _, err5 = box.execute('TRUNCATE TABLE t2;')
+    _, err6 = box.execute('TRUNCATE TABLE t_does_not_exist;')
 
     box.execute('DROP TRIGGER t2t;')
 
@@ -201,11 +201,11 @@ function monster_ddl_is_clean()
 end$
 function monster_ddl_check()
     local _, err1, err2, err3, err4, res
-    _, err1 = pcall(box.execute, 'INSERT INTO t2 VALUES (1, 1, 101)')
+    _, err1 = box.execute('INSERT INTO t2 VALUES (1, 1, 101)')
     box.execute('INSERT INTO t2 VALUES (1, 1, 1)')
-    _, err2 = pcall(box.execute, 'INSERT INTO t2 VALUES(2, 2, 1)')
-    _, err3 = pcall(box.execute, 'INSERT INTO t1 VALUES(1, 20, 1)')
-    _, err4 = pcall(box.execute, 'INSERT INTO t1 VALUES(1, -1, 1)')
+    _, err2 = box.execute('INSERT INTO t2 VALUES(2, 2, 1)')
+    _, err3 = box.execute('INSERT INTO t1 VALUES(1, 20, 1)')
+    _, err4 = box.execute('INSERT INTO t1 VALUES(1, -1, 1)')
     box.execute('INSERT INTO t1 VALUES (1, 1, 1)')
     res = box.execute('SELECT * FROM trigger_catcher')
     assert(box.space.T_RENAMED ~= nil)
@@ -217,7 +217,7 @@ end$
 function monster_ddl_clear()
     box.execute('DROP TRIGGER IF EXISTS t1t;')
     box.execute('DROP TABLE IF EXISTS trigger_catcher;')
-    pcall(box.execute, 'ALTER TABLE t1 DROP CONSTRAINT fk1;')
+    box.execute('ALTER TABLE t1 DROP CONSTRAINT fk1;')
     box.execute('DROP TABLE IF EXISTS t2')
     box.execute('DROP TABLE IF EXISTS t1')
     box.execute('DROP TABLE IF EXISTS t_renamed')
diff --git a/test/sql/delete.result b/test/sql/delete.result
index 0bc389f23..e27c79d85 100644
--- a/test/sql/delete.result
+++ b/test/sql/delete.result
@@ -57,7 +57,8 @@ box.execute("DROP TABLE t1;");
 --
 box.execute("DELETE FROM t1;")
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.execute("CREATE TABLE t2 (s1 INT PRIMARY KEY);")
 ---
@@ -69,7 +70,8 @@ box.execute("CREATE TRIGGER t2 BEFORE INSERT ON t2 FOR EACH ROW BEGIN DELETE FRO
 ...
 box.execute("INSERT INTO t2 VALUES (0);")
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.execute("DROP TABLE t2;")
 ---
@@ -81,7 +83,8 @@ box.execute("DROP TABLE t2;")
 -- can't truncate system table.
 box.execute("TRUNCATE TABLE \"_fk_constraint\";")
 ---
-- error: Can't truncate a system space, space '_fk_constraint'
+- null
+- Can't truncate a system space, space '_fk_constraint'
 ...
 box.execute("CREATE TABLE t1(id INT PRIMARY KEY, a INT, b TEXT);")
 ---
@@ -128,8 +131,9 @@ box.execute("CREATE VIEW v1 AS SELECT * FROM t1;")
 ...
 box.execute("TRUNCATE TABLE v1;")
 ---
-- error: 'Failed to execute SQL statement: can not truncate space ''V1'' because space
-    is a view'
+- null
+- 'Failed to execute SQL statement: can not truncate space ''V1'' because space is
+  a view'
 ...
 -- Can't truncate table with FK.
 box.execute("CREATE TABLE t2(x INT PRIMARY KEY REFERENCES t1(id));")
@@ -138,8 +142,9 @@ box.execute("CREATE TABLE t2(x INT PRIMARY KEY REFERENCES t1(id));")
 ...
 box.execute("TRUNCATE TABLE t1;")
 ---
-- error: 'Failed to execute SQL statement: can not truncate space ''T1'' because other
-    objects depend on it'
+- null
+- 'Failed to execute SQL statement: can not truncate space ''T1'' because other objects
+  depend on it'
 ...
 -- Table triggers should be ignored.
 box.execute("DROP TABLE t2;")
diff --git a/test/sql/drop-table.result b/test/sql/drop-table.result
index 48b0010ac..af8fe3863 100644
--- a/test/sql/drop-table.result
+++ b/test/sql/drop-table.result
@@ -32,7 +32,8 @@ box.execute("DROP TABLE zzzoobar")
 -- Table does not exist anymore. Should error here.
 box.execute("INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
 ---
-- error: Space 'ZZZOOBAR' does not exist
+- null
+- Space 'ZZZOOBAR' does not exist
 ...
 -- gh-3712: if space features sequence, data from _sequence_data
 -- must be deleted before space is dropped.
@@ -97,12 +98,14 @@ box.session.su('tmp')
 --
 box.execute('CREATE TABLE t1 (id INT PRIMARY KEY, a INT)')
 ---
-- error: Write access to space '_index' is denied for user 'tmp'
+- null
+- Write access to space '_index' is denied for user 'tmp'
 ...
 -- Error: no such table.
 box.execute('DROP TABLE t1')
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.session.su('admin')
 ---
@@ -138,7 +141,8 @@ box.session.su('tmp')
 --
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY AUTOINCREMENT, a INT UNIQUE, b INT UNIQUE, c INT UNIQUE, d INT UNIQUE)')
 ---
-- error: Write access to space '_sequence' is denied for user 'tmp'
+- null
+- Write access to space '_sequence' is denied for user 'tmp'
 ...
 box.session.su('admin')
 ---
@@ -180,8 +184,8 @@ box.execute('CREATE TABLE t3(a INTEGER PRIMARY KEY);')
 --
 box.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES t3, a INT UNIQUE, c TEXT REFERENCES t3);')
 ---
-- error: 'Failed to create foreign key constraint ''FK_CONSTRAINT_2_T4'': field type
-    mismatch'
+- null
+- 'Failed to create foreign key constraint ''FK_CONSTRAINT_2_T4'': field type mismatch'
 ...
 box.execute('DROP TABLE t3;')
 ---
diff --git a/test/sql/errinj.result b/test/sql/errinj.result
index 2fc1ae0cc..ea570f0dc 100644
--- a/test/sql/errinj.result
+++ b/test/sql/errinj.result
@@ -189,11 +189,13 @@ box.error.injection.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("CREATE TRIGGER t1t INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES (1, 1); END;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.execute("CREATE INDEX t1a ON t1(a);")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.error.injection.set("ERRINJ_WAL_IO", false)
 ---
@@ -257,7 +259,8 @@ box.error.injection.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("DROP TRIGGER t1t;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.error.injection.set("ERRINJ_WAL_IO", false)
 ---
@@ -334,7 +337,8 @@ errinj.set("ERRINJ_WAL_IO", false)
 ...
 box.execute("INSERT INTO t3 VALUES (1, 2, 2);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 errinj.set("ERRINJ_WAL_IO", true)
 ---
@@ -342,7 +346,8 @@ errinj.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("ALTER TABLE t3 ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES t3;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 errinj.set("ERRINJ_WAL_IO", false)
 ---
@@ -366,7 +371,8 @@ box.execute("ALTER TABLE t3 ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES t3;")
 ...
 box.execute("INSERT INTO t3 VALUES(1, 1, 3);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 errinj.set("ERRINJ_WAL_IO", true)
 ---
@@ -374,11 +380,13 @@ errinj.set("ERRINJ_WAL_IO", true)
 ...
 box.execute("ALTER TABLE t3 DROP CONSTRAINT fk1;")
 ---
-- error: Failed to write to disk
+- null
+- Failed to write to disk
 ...
 box.execute("INSERT INTO t3 VALUES(1, 1, 3);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 errinj.set("ERRINJ_WAL_IO", false)
 ---
@@ -400,7 +408,8 @@ errinj.set("ERRINJ_SQL_NAME_NORMALIZATION", true)
 ...
 box.execute("CREATE TABLE hello (id INT primary key,x INT,y INT);")
 ---
-- error: Failed to allocate 6 bytes in sqlDbMallocRawNN for res
+- null
+- Failed to allocate 6 bytes in sqlDbMallocRawNN for res
 ...
 dummy_f = function(int) return 1 end
 ---
@@ -440,7 +449,8 @@ _ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<
 ...
 box.execute("INSERT INTO \"test\" VALUES(5);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<5'
 ...
 errinj.set("ERRINJ_WAL_IO", true)
 ---
@@ -471,7 +481,8 @@ _ = box.space._ck_constraint:delete({s.id, 'CK_CONSTRAINT_01'})
 ...
 box.execute("INSERT INTO \"test\" VALUES(6);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_01'': X<=5'
 ...
 errinj.set("ERRINJ_WAL_IO", false)
 ---
@@ -507,11 +518,13 @@ _ = box.space._ck_constraint:insert({s.id, 'Xgreater10', false, 'SQL', 'X > 10'}
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''Xgreater10'': X > 10'
+- null
+- 'Check constraint failed ''Xgreater10'': X > 10'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 10);")
 ---
-- error: 'Check constraint failed ''XlessY'': X < Y'
+- null
+- 'Check constraint failed ''XlessY'': X < Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 100);")
 ---
@@ -534,11 +547,13 @@ errinj.set("ERRINJ_WAL_IO", false)
 ...
 box.execute("INSERT INTO \"test\" VALUES(1, 2);")
 ---
-- error: 'Check constraint failed ''Xgreater10'': X > 10'
+- null
+- 'Check constraint failed ''Xgreater10'': X > 10'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 10);")
 ---
-- error: 'Check constraint failed ''XlessY'': X < Y'
+- null
+- 'Check constraint failed ''XlessY'': X < Y'
 ...
 box.execute("INSERT INTO \"test\" VALUES(20, 100);")
 ---
diff --git a/test/sql/foreign-keys.result b/test/sql/foreign-keys.result
index f3cca5c80..38b0b1424 100644
--- a/test/sql/foreign-keys.result
+++ b/test/sql/foreign-keys.result
@@ -181,7 +181,8 @@ t = box.space._fk_constraint:insert(t)
 --
 box.execute("DROP INDEX i1 on t1;")
 ---
-- error: 'Can''t modify space ''T1'': can not drop a referenced index'
+- null
+- 'Can''t modify space ''T1'': can not drop a referenced index'
 ...
 -- Referenced index can't be altered as well, if alter leads to
 -- rebuild of index (e.g. index still can be renamed).
@@ -395,21 +396,23 @@ box.execute('CREATE TABLE t1 (id INT PRIMARY KEY);')
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE RESTRICT);')
 ---
-- error: Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an
-    identifier.
+- null
+- Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an identifier.
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE CASCADE);')
 ---
-- error: Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an
-    identifier.
+- null
+- Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an identifier.
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON UPDATE RESTRICT ON DELETE RESTRICT);')
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE MATCH FULL);')
 ---
-- error: Keyword 'MATCH' is reserved. Please use double quotes if 'MATCH' is an identifier.
+- null
+- Keyword 'MATCH' is reserved. Please use double quotes if 'MATCH' is an identifier.
 ...
 box.space.T1:drop()
 ---
@@ -436,16 +439,18 @@ i1 = box.space.T2:create_index('I1')
 ...
 box.execute("ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (id) REFERENCES t2;")
 ---
-- error: 'Failed to create foreign key constraint ''FK'': foreign key refers to nonexistent
-    field'
+- null
+- 'Failed to create foreign key constraint ''FK'': foreign key refers to nonexistent
+  field'
 ...
 -- Make sure that if referenced columns (of parent space) are
 -- ommitted and parent space doesn't have PK, then error is raised.
 --
 box.execute("ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY (id) REFERENCES t1;")
 ---
-- error: 'Failed to create foreign key constraint ''FK'': referenced space doesn''t
-    feature PRIMARY KEY'
+- null
+- 'Failed to create foreign key constraint ''FK'': referenced space doesn''t feature
+  PRIMARY KEY'
 ...
 t1:drop()
 ---
diff --git a/test/sql/gh-2929-primary-key.result b/test/sql/gh-2929-primary-key.result
index 815b16e0b..021d03760 100644
--- a/test/sql/gh-2929-primary-key.result
+++ b/test/sql/gh-2929-primary-key.result
@@ -20,19 +20,23 @@ box.execute("CREATE TABLE t1(a INT PRIMARY KEY, b INT UNIQUE)")
 ...
 box.execute("CREATE TABLE t2(a INT UNIQUE, b INT)")
 ---
-- error: 'Failed to create space ''T2'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T2'': PRIMARY KEY missing'
 ...
 box.execute("CREATE TABLE t3(a NUMBER)")
 ---
-- error: 'Failed to create space ''T3'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T3'': PRIMARY KEY missing'
 ...
 box.execute("CREATE TABLE t4(a NUMBER, b TEXT)")
 ---
-- error: 'Failed to create space ''T4'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T4'': PRIMARY KEY missing'
 ...
 box.execute("CREATE TABLE t5(a NUMBER, b NUMBER UNIQUE)")
 ---
-- error: 'Failed to create space ''T5'': PRIMARY KEY missing'
+- null
+- 'Failed to create space ''T5'': PRIMARY KEY missing'
 ...
 box.execute("DROP TABLE t1")
 ---
@@ -43,5 +47,6 @@ box.execute("DROP TABLE t1")
 --
 box.execute("CREATE TABLE tx (a INT, PRIMARY KEY (b));")
 ---
-- error: Can’t resolve field 'B'
+- null
+- Can’t resolve field 'B'
 ...
diff --git a/test/sql/gh-2981-check-autoinc.result b/test/sql/gh-2981-check-autoinc.result
index f03858a7c..64ae64bcd 100644
--- a/test/sql/gh-2981-check-autoinc.result
+++ b/test/sql/gh-2981-check-autoinc.result
@@ -29,7 +29,8 @@ box.execute("insert into t1 values (18, null);")
 ...
 box.execute("insert into t1(s2) values (null);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': s1 <> 19'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': s1 <> 19'
 ...
 box.execute("insert into t2 values (18, null);")
 ---
@@ -37,7 +38,8 @@ box.execute("insert into t2 values (18, null);")
 ...
 box.execute("insert into t2(s2) values (null);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
 ...
 box.execute("insert into t2 values (24, null);")
 ---
@@ -45,7 +47,8 @@ box.execute("insert into t2 values (24, null);")
 ...
 box.execute("insert into t2(s2) values (null);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T2'': s1 <> 19 AND s1 <> 25'
 ...
 box.execute("insert into t3 values (9, null)")
 ---
@@ -53,7 +56,8 @@ box.execute("insert into t3 values (9, null)")
 ...
 box.execute("insert into t3(s2) values (null)")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T3'': s1 < 10'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T3'': s1 < 10'
 ...
 box.execute("DROP TABLE t1")
 ---
diff --git a/test/sql/gh-3613-idx-alter-update.result b/test/sql/gh-3613-idx-alter-update.result
index 20315df0b..ba323a625 100644
--- a/test/sql/gh-3613-idx-alter-update.result
+++ b/test/sql/gh-3613-idx-alter-update.result
@@ -33,7 +33,8 @@ box.snapshot()
 test_run:cmd('restart server default')
 box.execute('DROP INDEX i ON j3')
 ---
-- error: No index 'I' is defined in space 'J3'
+- null
+- No index 'I' is defined in space 'J3'
 ...
 box.execute('CREATE INDEX i ON j3 (s1)')
 ---
diff --git a/test/sql/gh-3888-values-blob-assert.result b/test/sql/gh-3888-values-blob-assert.result
index 81b0f52fd..768448c91 100644
--- a/test/sql/gh-3888-values-blob-assert.result
+++ b/test/sql/gh-3888-values-blob-assert.result
@@ -17,30 +17,36 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 -- check 'VALUES' against typedef keywords (should fail)
 box.execute('VALUES(scalar)')
 ---
-- error: Syntax error near 'scalar'
+- null
+- Syntax error near 'scalar'
 ...
 box.execute('VALUES(float)')
 ---
-- error: Syntax error near 'float'
+- null
+- Syntax error near 'float'
 ...
 -- check 'SELECT' against typedef keywords (should fail)
 box.execute('SELECT scalar')
 ---
-- error: Syntax error near 'scalar'
+- null
+- Syntax error near 'scalar'
 ...
 box.execute('SELECT float')
 ---
-- error: Syntax error near 'float'
+- null
+- Syntax error near 'float'
 ...
 -- check 'VALUES' against ID (should fail)
 box.execute('VALUES(TheColumnName)')
 ---
-- error: Can’t resolve field 'THECOLUMNNAME'
+- null
+- Can’t resolve field 'THECOLUMNNAME'
 ...
 -- check 'SELECT' against ID (should fail)
 box.execute('SELECT TheColumnName')
 ---
-- error: Can’t resolve field 'THECOLUMNNAME'
+- null
+- Can’t resolve field 'THECOLUMNNAME'
 ...
 -- check 'VALUES' well-formed expression  (returns value)
 box.execute('VALUES(-0.5e-2)')
diff --git a/test/sql/icu-upper-lower.result b/test/sql/icu-upper-lower.result
index dc00c03f8..88266c8c5 100644
--- a/test/sql/icu-upper-lower.result
+++ b/test/sql/icu-upper-lower.result
@@ -276,13 +276,16 @@ test_run:cmd("setopt delimiter ''");
 -- Bad test cases
 box.execute("select upper('1', 2)")
 ---
-- error: wrong number of arguments to function UPPER()
+- null
+- wrong number of arguments to function UPPER()
 ...
 box.execute("select upper(\"1\")")
 ---
-- error: Can’t resolve field '1'
+- null
+- Can’t resolve field '1'
 ...
 box.execute("select upper()")
 ---
-- error: wrong number of arguments to function UPPER()
+- null
+- wrong number of arguments to function UPPER()
 ...
diff --git a/test/sql/insert-unique.result b/test/sql/insert-unique.result
index 236046f30..1cf44c95e 100644
--- a/test/sql/insert-unique.result
+++ b/test/sql/insert-unique.result
@@ -28,12 +28,14 @@ box.execute("INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- PK must be unique
 box.execute("INSERT INTO zoobar VALUES (112, 222, 'c3', 444)")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_ZOOBAR_1' in space 'ZOOBAR'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_ZOOBAR_1' in space 'ZOOBAR'
 ...
 -- Unique index must be respected
 box.execute("INSERT INTO zoobar VALUES (111, 223, 'c3', 444)")
 ---
-- error: Duplicate key exists in unique index 'ZOOBAR2' in space 'ZOOBAR'
+- null
+- Duplicate key exists in unique index 'ZOOBAR2' in space 'ZOOBAR'
 ...
 -- Cleanup
 box.execute("DROP INDEX zoobar2 ON zoobar")
diff --git a/test/sql/integer-overflow.result b/test/sql/integer-overflow.result
index a9a90f539..223ba023e 100644
--- a/test/sql/integer-overflow.result
+++ b/test/sql/integer-overflow.result
@@ -14,7 +14,8 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.execute('SELECT (2147483647 * 2147483647 * 2147483647);')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT (-9223372036854775808 / -1);')
 ---
@@ -26,7 +27,8 @@ box.execute('SELECT (-9223372036854775808 / -1);')
 ...
 box.execute('SELECT (-9223372036854775808 - 1);')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT (9223372036854775807 + 1);')
 ---
@@ -38,11 +40,13 @@ box.execute('SELECT (9223372036854775807 + 1);')
 ...
 box.execute('SELECT (9223372036854775807 + 9223372036854775807 + 2);')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT 18446744073709551615 * 2;')
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute('SELECT (-9223372036854775807 * (-2));')
 ---
@@ -64,8 +68,9 @@ box.execute('SELECT 9223372036854775808;')
 ...
 box.execute('SELECT -9223372036854775809;')
 ---
-- error: Integer literal -9223372036854775809 exceeds the supported range [-9223372036854775808,
-    18446744073709551615]
+- null
+- Integer literal -9223372036854775809 exceeds the supported range [-9223372036854775808,
+  18446744073709551615]
 ...
 box.execute('SELECT 9223372036854775808 - 1;')
 ---
@@ -85,8 +90,9 @@ box.execute('SELECT 18446744073709551615;')
 ...
 box.execute('SELECT 18446744073709551616;')
 ---
-- error: Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808,
-    18446744073709551615]
+- null
+- Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808,
+  18446744073709551615]
 ...
 -- Test that CAST may also leads to overflow.
 --
@@ -100,7 +106,8 @@ box.execute('SELECT CAST(\'9223372036854775808\' AS INTEGER);')
 ...
 box.execute('SELECT CAST(\'18446744073709551616\' AS INTEGER);')
 ---
-- error: 'Type mismatch: can not convert 18446744073709551616 to integer'
+- null
+- 'Type mismatch: can not convert 18446744073709551616 to integer'
 ...
 -- Due to inexact represantation of large integers in terms of
 -- floating point numbers, numerics with value < INT64_MAX
@@ -110,7 +117,8 @@ box.execute('SELECT CAST(\'18446744073709551616\' AS INTEGER);')
 --
 box.execute('SELECT CAST(9223372036854775807.0 AS INTEGER);')
 ---
-- error: 'Type mismatch: can not convert 9.22337203685478e+18 to integer'
+- null
+- 'Type mismatch: can not convert 9.22337203685478e+18 to integer'
 ...
 -- gh-3810: make sure that if space contains integers in range
 -- [INT64_MAX, UINT64_MAX], they are handled inside SQL in a
diff --git a/test/sql/message-func-indexes.result b/test/sql/message-func-indexes.result
index eb2d6c7fa..69e3ee05d 100644
--- a/test/sql/message-func-indexes.result
+++ b/test/sql/message-func-indexes.result
@@ -21,7 +21,8 @@ box.execute("CREATE TABLE t2(object INTEGER PRIMARY KEY, price INTEGER, count IN
 -- should return certain message.
 box.execute("CREATE INDEX i1 ON t1(a+1)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 box.execute("CREATE INDEX i2 ON t1(a)")
 ---
@@ -29,7 +30,8 @@ box.execute("CREATE INDEX i2 ON t1(a)")
 ...
 box.execute("CREATE INDEX i3 ON t2(price + 100)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 box.execute("CREATE INDEX i4 ON t2(price)")
 ---
@@ -37,11 +39,13 @@ box.execute("CREATE INDEX i4 ON t2(price)")
 ...
 box.execute("CREATE INDEX i5 ON t2(count + 1)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 box.execute("CREATE INDEX i6 ON t2(count * price)")
 ---
-- error: Tarantool does not support functional indexes
+- null
+- Tarantool does not support functional indexes
 ...
 -- Cleaning up.
 box.execute("DROP TABLE t1")
diff --git a/test/sql/misc.result b/test/sql/misc.result
index bc8b10e87..e9bfe89b2 100644
--- a/test/sql/misc.result
+++ b/test/sql/misc.result
@@ -19,13 +19,13 @@ box.execute('select 1;')
 ...
 box.execute('select 1; select 2;')
 ---
-- error: Keyword 'select' is reserved. Please use double quotes if 'select' is an
-    identifier.
+- null
+- Keyword 'select' is reserved. Please use double quotes if 'select' is an identifier.
 ...
 box.execute('create table t1 (id INT primary key); select 100;')
 ---
-- error: Keyword 'select' is reserved. Please use double quotes if 'select' is an
-    identifier.
+- null
+- Keyword 'select' is reserved. Please use double quotes if 'select' is an identifier.
 ...
 box.space.t1 == nil
 ---
@@ -33,35 +33,40 @@ box.space.t1 == nil
 ...
 box.execute(';')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 box.execute('')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 box.execute('     ;')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 box.execute('\n\n\n\t\t\t   ')
 ---
-- error: Failed to execute an empty SQL statement
+- null
+- Failed to execute an empty SQL statement
 ...
 -- gh-3820: only table constraints can have a name.
 --
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b INTEGER CONSTRAINT c1 NULL)')
 ---
-- error: Keyword 'NULL' is reserved. Please use double quotes if 'NULL' is an identifier.
+- null
+- Keyword 'NULL' is reserved. Please use double quotes if 'NULL' is an identifier.
 ...
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b INTEGER CONSTRAINT c1 DEFAULT 300)')
 ---
-- error: Keyword 'DEFAULT' is reserved. Please use double quotes if 'DEFAULT' is an
-    identifier.
+- null
+- Keyword 'DEFAULT' is reserved. Please use double quotes if 'DEFAULT' is an identifier.
 ...
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b TEXT CONSTRAINT c1 COLLATE "binary")')
 ---
-- error: Keyword 'COLLATE' is reserved. Please use double quotes if 'COLLATE' is an
-    identifier.
+- null
+- Keyword 'COLLATE' is reserved. Please use double quotes if 'COLLATE' is an identifier.
 ...
 -- Make sure that type of literals in meta complies with its real
 -- type. For instance, typeof(0.5) is number, not integer.
diff --git a/test/sql/no-pk-space.result b/test/sql/no-pk-space.result
index f4f6059a2..025f363b3 100644
--- a/test/sql/no-pk-space.result
+++ b/test/sql/no-pk-space.result
@@ -19,19 +19,23 @@ s = box.schema.create_space('test', {format = format})
 ...
 box.execute("SELECT * FROM \"test\";")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("INSERT INTO \"test\" VALUES (1);")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("DELETE FROM \"test\";")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.execute("UPDATE \"test\" SET id = 3;")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 s:drop()
 ---
@@ -54,7 +58,8 @@ box.space.T1:drop()
 ...
 box.execute("SELECT * FROM v1;")
 ---
-- error: SQL does not support spaces without primary key
+- null
+- SQL does not support spaces without primary key
 ...
 box.space.V1:drop()
 ---
diff --git a/test/sql/on-conflict.result b/test/sql/on-conflict.result
index 2c3dfa743..6851e217e 100644
--- a/test/sql/on-conflict.result
+++ b/test/sql/on-conflict.result
@@ -14,57 +14,69 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT ABORT)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE q (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT FAIL)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE p (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT IGNORE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE g (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT REPLACE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE e (id INTEGER PRIMARY KEY ON CONFLICT REPLACE, v INTEGER)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE t1(a INT PRIMARY KEY ON CONFLICT REPLACE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.execute("CREATE TABLE t2(a INT PRIMARY KEY ON CONFLICT IGNORE)")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 -- CHECK constraint is illegal with REPLACE option.
 --
 box.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER CHECK (a > 5) ON CONFLICT REPLACE);")
 ---
-- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- null
+- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 --
 -- gh-3473: Primary key can't be declared with NULL.
 --
 box.execute("CREATE TABLE te17 (s1 INT NULL PRIMARY KEY NOT NULL);")
 ---
-- error: Primary index of space 'TE17' can not contain nullable parts
+- null
+- Primary index of space 'TE17' can not contain nullable parts
 ...
 box.execute("CREATE TABLE te17 (s1 INT NULL PRIMARY KEY);")
 ---
-- error: Primary index of space 'TE17' can not contain nullable parts
+- null
+- Primary index of space 'TE17' can not contain nullable parts
 ...
 box.execute("CREATE TABLE test (a int PRIMARY KEY, b int NULL ON CONFLICT IGNORE);")
 ---
-- error: 'Failed to execute SQL statement: NULL declaration for column ''B'' of table
-    ''TEST'' has been already set to ''none'''
+- null
+- 'Failed to execute SQL statement: NULL declaration for column ''B'' of table ''TEST''
+  has been already set to ''none'''
 ...
 box.execute("CREATE TABLE test (a int, b int NULL, c int, PRIMARY KEY(a, b, c))")
 ---
-- error: Primary index of space 'TEST' can not contain nullable parts
+- null
+- Primary index of space 'TEST' can not contain nullable parts
 ...
 -- Several NOT NULL REPLACE constraints work
 --
diff --git a/test/sql/persistency.result b/test/sql/persistency.result
index fcb5d2362..f8f992c39 100644
--- a/test/sql/persistency.result
+++ b/test/sql/persistency.result
@@ -31,7 +31,8 @@ box.execute("INSERT INTO foobar VALUES (1000, 'foobar')")
 ...
 box.execute("INSERT INTO foobar VALUES (1, 'duplicate')")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
 ...
 -- simple select
 box.execute("SELECT bar, foo, 42, 'awesome' FROM foobar")
@@ -369,7 +370,8 @@ box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"");
 -- ... functional
 box.execute("INSERT INTO foobar VALUES ('foobar trigger test', 8888)")
 ---
-- error: 'Type mismatch: can not convert foobar trigger test to integer'
+- null
+- 'Type mismatch: can not convert foobar trigger test to integer'
 ...
 box.execute("SELECT * FROM barfoo WHERE foo = 9999");
 ---
@@ -400,7 +402,8 @@ box.execute("DROP TRIGGER tfoobar")
 -- Should error
 box.execute("DROP TRIGGER tfoobar")
 ---
-- error: Trigger 'TFOOBAR' doesn't exist
+- null
+- Trigger 'TFOOBAR' doesn't exist
 ...
 -- Should be empty
 box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"")
@@ -415,7 +418,8 @@ box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"")
 -- prove barfoo2 still exists
 box.execute("INSERT INTO barfoo VALUES ('xfoo', 1)")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
 ...
 box.execute("SELECT * FROM barfoo")
 ---
diff --git a/test/sql/row-count.result b/test/sql/row-count.result
index ed7e319a9..fb96e213c 100644
--- a/test/sql/row-count.result
+++ b/test/sql/row-count.result
@@ -272,7 +272,8 @@ box.execute("SELECT ROW_COUNT();")
 ...
 box.execute("COMMIT;")
 ---
-- error: 'Failed to execute SQL statement: cannot commit - no transaction is active'
+- null
+- 'Failed to execute SQL statement: cannot commit - no transaction is active'
 ...
 box.execute("SELECT ROW_COUNT();")
 ---
diff --git a/test/sql/savepoints.result b/test/sql/savepoints.result
index d20e0ed7a..78957173e 100644
--- a/test/sql/savepoints.result
+++ b/test/sql/savepoints.result
@@ -14,15 +14,18 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.execute('SAVEPOINT t1;');
 ---
-- error: No active transaction
+- null
+- No active transaction
 ...
 box.execute('RELEASE SAVEPOINT t1;');
 ---
-- error: No active transaction
+- null
+- No active transaction
 ...
 box.execute('ROLLBACK TO SAVEPOINT t1;');
 ---
-- error: No active transaction
+- null
+- No active transaction
 ...
 box.begin() box.execute('SAVEPOINT t1;') box.execute('RELEASE SAVEPOINT t1;') box.commit();
 ---
@@ -61,13 +64,16 @@ release_sv_fail = function()
     box.execute('SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t1;')
-    box.execute('ROLLBACK TO t1;')
+    local _, err = box.execute('ROLLBACK TO t1;')
+    if err ~= nil then
+        return err
+    end
 end;
 ---
 ...
 release_sv_fail();
 ---
-- error: 'Can not rollback to savepoint: the savepoint does not exist'
+- 'Can not rollback to savepoint: the savepoint does not exist'
 ...
 box.commit();
 ---
diff --git a/test/sql/savepoints.test.lua b/test/sql/savepoints.test.lua
index b4c6fee07..d96b04600 100644
--- a/test/sql/savepoints.test.lua
+++ b/test/sql/savepoints.test.lua
@@ -37,7 +37,10 @@ release_sv_fail = function()
     box.execute('SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t2;')
     box.execute('RELEASE SAVEPOINT t1;')
-    box.execute('ROLLBACK TO t1;')
+    local _, err = box.execute('ROLLBACK TO t1;')
+    if err ~= nil then
+        return err
+    end
 end;
 release_sv_fail();
 box.commit();
diff --git a/test/sql/transition.result b/test/sql/transition.result
index e7794742e..9738092fe 100644
--- a/test/sql/transition.result
+++ b/test/sql/transition.result
@@ -28,7 +28,8 @@ box.execute("INSERT INTO foobar VALUES (1000, 'foobar')")
 ...
 box.execute("INSERT INTO foobar VALUES (1, 'duplicate')")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_FOOBAR_1' in space 'FOOBAR'
 ...
 -- simple select
 box.execute("SELECT bar, foo, 42, 'awesome' FROM foobar")
@@ -311,7 +312,8 @@ box.execute("INSERT INTO barfoo VALUES ('foobar', 1000)")
 -- prove barfoo2 was created
 box.execute("INSERT INTO barfoo VALUES ('xfoo', 1)")
 ---
-- error: Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
+- null
+- Duplicate key exists in unique index 'pk_unnamed_BARFOO_1' in space 'BARFOO'
 ...
 box.execute("SELECT foo, bar FROM barfoo")
 ---
@@ -383,8 +385,8 @@ box.execute("DROP TABLE barfoo")
 -- attempt to create a table lacking PRIMARY KEY
 box.execute("CREATE TABLE without_rowid_lacking_primary_key(x SCALAR)")
 ---
-- error: 'Failed to create space ''WITHOUT_ROWID_LACKING_PRIMARY_KEY'': PRIMARY KEY
-    missing'
+- null
+- 'Failed to create space ''WITHOUT_ROWID_LACKING_PRIMARY_KEY'': PRIMARY KEY missing'
 ...
 -- create a table with implicit indices (used to SEGFAULT)
 box.execute("CREATE TABLE implicit_indices(a INT PRIMARY KEY,b INT,c INT,d TEXT UNIQUE)")
diff --git a/test/sql/transitive-transactions.result b/test/sql/transitive-transactions.result
index ee9b4218d..29c7316db 100644
--- a/test/sql/transitive-transactions.result
+++ b/test/sql/transitive-transactions.result
@@ -39,13 +39,16 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y) D
 fk_violation_1 = function()
     box.begin()
     box.execute('INSERT INTO child VALUES (1, 1);')
-    box.execute('COMMIT;')
+    local _, err = box.execute('COMMIT;')
+    if err ~= nil then
+        return err
+    end
 end;
 ---
 ...
 fk_violation_1();
 ---
-- error: 'Can not commit transaction: deferred foreign keys violations are not resolved'
+- 'Can not commit transaction: deferred foreign keys violations are not resolved'
 ...
 box.space.CHILD:select();
 ---
@@ -92,7 +95,10 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y))'
 
 fk_defer = function()
     box.begin()
-    box.execute('INSERT INTO child VALUES (1, 2);')
+    local _, err = box.execute('INSERT INTO child VALUES (1, 2);')
+    if err ~= nil then
+        return err
+    end
     box.execute('INSERT INTO parent VALUES (2, 2);')
     box.commit()
 end;
@@ -100,7 +106,7 @@ end;
 ...
 fk_defer();
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.space.CHILD:select();
 ---
diff --git a/test/sql/transitive-transactions.test.lua b/test/sql/transitive-transactions.test.lua
index 54f12739e..4633f078d 100644
--- a/test/sql/transitive-transactions.test.lua
+++ b/test/sql/transitive-transactions.test.lua
@@ -19,7 +19,10 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y) D
 fk_violation_1 = function()
     box.begin()
     box.execute('INSERT INTO child VALUES (1, 1);')
-    box.execute('COMMIT;')
+    local _, err = box.execute('COMMIT;')
+    if err ~= nil then
+        return err
+    end
 end;
 fk_violation_1();
 box.space.CHILD:select();
@@ -49,7 +52,10 @@ box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y))'
 
 fk_defer = function()
     box.begin()
-    box.execute('INSERT INTO child VALUES (1, 2);')
+    local _, err = box.execute('INSERT INTO child VALUES (1, 2);')
+    if err ~= nil then
+        return err
+    end
     box.execute('INSERT INTO parent VALUES (2, 2);')
     box.commit()
 end;
diff --git a/test/sql/triggers.result b/test/sql/triggers.result
index 76e87c8f2..9dfe981a0 100644
--- a/test/sql/triggers.result
+++ b/test/sql/triggers.result
@@ -322,7 +322,8 @@ box.execute("INSERT INTO n VALUES (0, '',null);")
 ...
 box.execute("UPDATE m SET s1 = 'The Rain In Spain';")
 ---
-- error: A multi-statement transaction can not use multiple storage engines
+- null
+- A multi-statement transaction can not use multiple storage engines
 ...
 -- ANALYZE banned in gh-4069
 -- box.sql.execute("ANALYZE m;")
@@ -365,7 +366,8 @@ box.execute("INSERT INTO n VALUES (0, '',null);")
 ...
 box.execute("UPDATE m SET s1 = 'The Rain In Spain';")
 ---
-- error: A multi-statement transaction can not use multiple storage engines
+- null
+- A multi-statement transaction can not use multiple storage engines
 ...
 -- ANALYZE banned in gh-4069
 -- box.sql.execute("ANALYZE n;")
@@ -408,7 +410,8 @@ box.execute("INSERT INTO test VALUES (1)")
 ...
 box.execute("SELECT * FROM test2")
 ---
-- error: A multi-statement transaction can not use multiple storage engines
+- null
+- A multi-statement transaction can not use multiple storage engines
 ...
 box.execute("ROLLBACK;")
 ---
@@ -483,7 +486,8 @@ space_id = box.space.T1.id
 ...
 box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW WHEN new.a = ? BEGIN SELECT 1; END;")
 ---
-- error: bindings are not allowed in DDL
+- null
+- bindings are not allowed in DDL
 ...
 tuple = {"TR1", space_id, {sql = [[CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW WHEN new.a = ? BEGIN SELECT 1; END;]]}}
 ---
@@ -508,8 +512,8 @@ space_id = box.space.T1.id
 ...
 box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN ; END;")
 ---
-- error: FOR EACH STATEMENT triggers are not implemented, please supply FOR EACH ROW
-    clause
+- null
+- FOR EACH STATEMENT triggers are not implemented, please supply FOR EACH ROW clause
 ...
 box.execute("DROP TABLE t1;")
 ---
@@ -539,7 +543,8 @@ box.session.su('tester')
 --
 box.execute([[CREATE TRIGGER r1 AFTER INSERT ON t1 FOR EACH ROW BEGIN SELECT 1; END; ]])
 ---
-- error: Space 'T1' does not exist
+- null
+- Space 'T1' does not exist
 ...
 box.session.su('admin')
 ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 780a23d51..604f54116 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -8,26 +8,28 @@ test_run = env.new()
 --
 box.execute("CREATE TABLE t1 (id PRIMARY KEY);")
 ---
-- error: Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an
-    identifier.
+- null
+- Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an identifier.
 ...
 box.execute("CREATE TABLE t1 (a, id INT PRIMARY KEY);")
 ---
-- error: Syntax error near ','
+- null
+- Syntax error near ','
 ...
 box.execute("CREATE TABLE t1 (id PRIMARY KEY, a INT);")
 ---
-- error: Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an
-    identifier.
+- null
+- Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an identifier.
 ...
 box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a);")
 ---
-- error: Syntax error near ')'
+- null
+- Syntax error near ')'
 ...
 box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b UNIQUE);")
 ---
-- error: Keyword 'UNIQUE' is reserved. Please use double quotes if 'UNIQUE' is an
-    identifier.
+- null
+- Keyword 'UNIQUE' is reserved. Please use double quotes if 'UNIQUE' is an identifier.
 ...
 -- gh-3104: real type is stored in space format.
 --
@@ -152,33 +154,40 @@ sp:drop()
 --
 box.execute("SELECT 'abc' || 1;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
 ...
 box.execute("SELECT 'abc' || 1.123;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got REAL'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got REAL'
 ...
 box.execute("SELECT 1 || 'abc';")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
 ...
 box.execute("SELECT 1.123 || 'abc';")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got REAL'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got REAL'
 ...
 box.execute("SELECt 'a' || 'b' || 1;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got UNSIGNED'
 ...
 -- What is more, they must be of the same type.
 --
 box.execute("SELECT 'abc' || randomblob(5);")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT randomblob(5) || 'x';")
 ---
-- error: 'Inconsistent types: expected BLOB got TEXT'
+- null
+- 'Inconsistent types: expected BLOB got TEXT'
 ...
 -- Result of BLOBs concatenation must be BLOB.
 --
@@ -202,15 +211,18 @@ box.execute("INSERT INTO t1 VALUES (randomblob(5));")
 ...
 box.execute("SELECT * FROM t1 WHERE s LIKE 'blob';")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT * FROM t1 WHERE 'blob' LIKE s;")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT * FROM t1 WHERE 'blob' LIKE x'0000';")
 ---
-- error: 'Inconsistent types: expected TEXT got BLOB'
+- null
+- 'Inconsistent types: expected TEXT got BLOB'
 ...
 box.execute("SELECT s LIKE NULL FROM t1;")
 ---
@@ -230,11 +242,13 @@ box.execute("INSERT INTO t1 VALUES (1);")
 ...
 box.execute("SELECT * FROM t1 WHERE s LIKE 'int';")
 ---
-- error: 'Inconsistent types: expected TEXT got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT got UNSIGNED'
 ...
 box.execute("SELECT * FROM t1 WHERE 'int' LIKE 4;")
 ---
-- error: 'Inconsistent types: expected TEXT got UNSIGNED'
+- null
+- 'Inconsistent types: expected TEXT got UNSIGNED'
 ...
 box.execute("SELECT NULL LIKE s FROM t1;")
 ---
@@ -355,15 +369,18 @@ box.execute("SELECT unknown = true;")
 ...
 box.execute("SELECT 1 = true;")
 ---
-- error: 'Type mismatch: can not convert UNSIGNED to boolean'
+- null
+- 'Type mismatch: can not convert UNSIGNED to boolean'
 ...
 box.execute("SELECT 'abc' = true;")
 ---
-- error: 'Type mismatch: can not convert TEXT to boolean'
+- null
+- 'Type mismatch: can not convert TEXT to boolean'
 ...
 box.execute("SELECT 1.123 > true;")
 ---
-- error: 'Type mismatch: can not convert REAL to boolean'
+- null
+- 'Type mismatch: can not convert REAL to boolean'
 ...
 box.execute("SELECT true IN (1, 'abc', true)")
 ---
@@ -383,31 +400,37 @@ box.execute("SELECT true IN (1, 'abc', false)")
 ...
 box.execute("SELECT 1 LIMIT true;")
 ---
-- error: 'Failed to execute SQL statement: Only positive integers are allowed in the
-    LIMIT clause'
+- null
+- 'Failed to execute SQL statement: Only positive integers are allowed in the LIMIT
+  clause'
 ...
 box.execute("SELECT 1 LIMIT 1 OFFSET true;")
 ---
-- error: 'Failed to execute SQL statement: Only positive integers are allowed in the
-    OFFSET clause'
+- null
+- 'Failed to execute SQL statement: Only positive integers are allowed in the OFFSET
+  clause'
 ...
 box.execute("SELECT 'abc' || true;")
 ---
-- error: 'Inconsistent types: expected TEXT or BLOB got BOOLEAN'
+- null
+- 'Inconsistent types: expected TEXT or BLOB got BOOLEAN'
 ...
 -- Boolean can take part in arithmetic operations.
 --
 box.execute("SELECT true + false;")
 ---
-- error: 'Type mismatch: can not convert false to numeric'
+- null
+- 'Type mismatch: can not convert false to numeric'
 ...
 box.execute("SELECT true * 1;")
 ---
-- error: 'Type mismatch: can not convert true to numeric'
+- null
+- 'Type mismatch: can not convert true to numeric'
 ...
 box.execute("SELECT false / 0;")
 ---
-- error: 'Type mismatch: can not convert false to numeric'
+- null
+- 'Type mismatch: can not convert false to numeric'
 ...
 box.execute("SELECT not true;")
 ---
@@ -419,19 +442,23 @@ box.execute("SELECT not true;")
 ...
 box.execute("SELECT ~true;")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.execute("SELECT -true;")
 ---
-- error: 'Type mismatch: can not convert true to numeric'
+- null
+- 'Type mismatch: can not convert true to numeric'
 ...
 box.execute("SELECT true << 1;")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.execute("SELECT true | 1;")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.execute("SELECT true and false;")
 ---
@@ -553,22 +580,26 @@ box.execute("SELECT b FROM t GROUP BY b LIMIT 1;")
 ...
 box.execute("SELECT b FROM t LIMIT true;")
 ---
-- error: 'Failed to execute SQL statement: Only positive integers are allowed in the
-    LIMIT clause'
+- null
+- 'Failed to execute SQL statement: Only positive integers are allowed in the LIMIT
+  clause'
 ...
 -- Most of aggregates don't accept boolean arguments.
 --
 box.execute("SELECT sum(b) FROM t;")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT avg(b) FROM t;")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT total(b) FROM t;")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT min(b) FROM t;")
 ---
@@ -626,7 +657,8 @@ box.execute("SELECT upper(b) FROM t;")
 ...
 box.execute("SELECT abs(b) FROM t;")
 ---
-- error: 'Inconsistent types: expected number got boolean'
+- null
+- 'Inconsistent types: expected number got boolean'
 ...
 box.execute("SELECT typeof(b) FROM t;")
 ---
@@ -721,7 +753,8 @@ box.execute("ALTER TABLE t ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES parent
 ...
 box.execute("INSERT INTO t VALUES (1, true);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.execute("INSERT INTO parent VALUES (1, true);")
 ---
@@ -744,7 +777,8 @@ box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a BOOLEAN CHECK (a = true));")
 ...
 box.execute("INSERT INTO t1 VALUES (1, false);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a = true'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a = true'
 ...
 box.execute("INSERT INTO t1 VALUES (1, true);")
 ---
@@ -801,7 +835,8 @@ box.execute("SELECT CAST(true AS TEXT);")
 ...
 box.execute("SELECT CAST(true AS NUMBER);")
 ---
-- error: 'Type mismatch: can not convert true to number'
+- null
+- 'Type mismatch: can not convert true to number'
 ...
 box.execute("SELECT CAST(true AS SCALAR);")
 ---
@@ -845,7 +880,8 @@ box.execute("SELECT CAST(0.00000001 AS BOOLEAN);")
 ...
 box.execute("SELECT CAST('abc' AS BOOLEAN);")
 ---
-- error: 'Type mismatch: can not convert abc to boolean'
+- null
+- 'Type mismatch: can not convert abc to boolean'
 ...
 box.execute("SELECT CAST('  TrUe' AS BOOLEAN);")
 ---
@@ -865,11 +901,13 @@ box.execute("SELECT CAST('  falsE    ' AS BOOLEAN);")
 ...
 box.execute("SELECT CAST('  fals' AS BOOLEAN);")
 ---
-- error: 'Type mismatch: can not convert   fals to boolean'
+- null
+- 'Type mismatch: can not convert   fals to boolean'
 ...
 box.execute("SELECT CAST(X'4D6564766564' AS BOOLEAN);")
 ---
-- error: 'Type mismatch: can not convert Medved to boolean'
+- null
+- 'Type mismatch: can not convert Medved to boolean'
 ...
 -- Make sure that SCALAR can handle boolean values.
 --
@@ -895,11 +933,13 @@ box.execute("INSERT INTO t1 VALUES (3, 'abc'), (4, 12.5);")
 ...
 box.execute("SELECT s FROM t1 WHERE s = true;")
 ---
-- error: 'Type mismatch: can not convert TEXT to boolean'
+- null
+- 'Type mismatch: can not convert TEXT to boolean'
 ...
 box.execute("SELECT s FROM t1 WHERE s < true;")
 ---
-- error: 'Type mismatch: can not convert TEXT to boolean'
+- null
+- 'Type mismatch: can not convert TEXT to boolean'
 ...
 box.execute("SELECT s FROM t1 WHERE s IN (true, 1, 'abcd')")
 ---
@@ -924,7 +964,8 @@ box.execute("CREATE TABLE t1 (id INT PRIMARY KEY);")
 ...
 box.execute("INSERT INTO t1 VALUES (true);")
 ---
-- error: 'Type mismatch: can not convert true to integer'
+- null
+- 'Type mismatch: can not convert true to integer'
 ...
 box.space.T1:drop()
 ---
@@ -979,19 +1020,23 @@ box.execute("INSERT INTO tboolean VALUES (TRUE);")
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = x'44';")
 ---
-- error: 'Type mismatch: can not convert D to boolean'
+- null
+- 'Type mismatch: can not convert D to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 'abc';")
 ---
-- error: 'Type mismatch: can not convert abc to boolean'
+- null
+- 'Type mismatch: can not convert abc to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1;")
 ---
-- error: 'Type mismatch: can not convert UNSIGNED to boolean'
+- null
+- 'Type mismatch: can not convert UNSIGNED to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1.123;")
 ---
-- error: 'Type mismatch: can not convert REAL to boolean'
+- null
+- 'Type mismatch: can not convert REAL to boolean'
 ...
 box.space.TBOOLEAN:drop()
 ---
@@ -1268,7 +1313,8 @@ box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
 ...
 box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")
 ---
-- error: 'Type mismatch: can not convert 18446744073709551616 to integer'
+- null
+- 'Type mismatch: can not convert 18446744073709551616 to integer'
 ...
 box.execute("SELECT CAST('18446744073' || '709551615' AS INTEGER);")
 ---
@@ -1320,7 +1366,8 @@ box.execute("SELECT 18446744073709551615 / -9223372036854775808;")
 ...
 box.execute("SELECT 0 - 18446744073709551610;")
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute("CREATE TABLE t (id INT PRIMARY KEY, i INT);")
 ---
@@ -1378,7 +1425,8 @@ box.execute("SELECT i FROM t ORDER BY i;")
 ...
 box.execute("SELECT i FROM t ORDER BY -i;")
 ---
-- error: 'Failed to execute SQL statement: integer is overflowed'
+- null
+- 'Failed to execute SQL statement: integer is overflowed'
 ...
 box.execute("SELECT i FROM t ORDER BY i LIMIT 1;")
 ---
@@ -1569,7 +1617,8 @@ box.execute("ALTER TABLE t ADD CONSTRAINT fk1 FOREIGN KEY (i) REFERENCES parent
 ...
 box.execute("INSERT INTO t VALUES (1, 18446744073709551615);")
 ---
-- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
+- null
+- 'Failed to execute SQL statement: FOREIGN KEY constraint failed'
 ...
 box.execute("INSERT INTO parent VALUES (2, 18446744073709551615);")
 ---
@@ -1595,11 +1644,13 @@ box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT CHECK (a > 1844674407370
 ...
 box.execute("INSERT INTO t1 VALUES (1, 18446744073709551611);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
 ...
 box.execute("INSERT INTO t1 VALUES (1, -1);")
 ---
-- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
+- null
+- 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612'
 ...
 box.space.T1:drop()
 ---
@@ -1692,7 +1743,8 @@ box.execute("INSERT INTO t1 VALUES (0), (1), (2);")
 ...
 box.execute("INSERT INTO t1 VALUES (-3);")
 ---
-- error: 'Type mismatch: can not convert -3 to unsigned'
+- null
+- 'Type mismatch: can not convert -3 to unsigned'
 ...
 box.execute("SELECT id FROM t1;")
 ---
@@ -1714,7 +1766,8 @@ box.execute("SELECT CAST(123 AS UNSIGNED);")
 ...
 box.execute("SELECT CAST(-123 AS UNSIGNED);")
 ---
-- error: 'Type mismatch: can not convert -123 to unsigned'
+- null
+- 'Type mismatch: can not convert -123 to unsigned'
 ...
 box.execute("SELECT CAST(1.5 AS UNSIGNED);")
 ---
@@ -1726,7 +1779,8 @@ box.execute("SELECT CAST(1.5 AS UNSIGNED);")
 ...
 box.execute("SELECT CAST(-1.5 AS UNSIGNED);")
 ---
-- error: 'Type mismatch: can not convert -1 to unsigned'
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
 ...
 box.execute("SELECT CAST(true AS UNSIGNED);")
 ---
@@ -1746,7 +1800,8 @@ box.execute("SELECT CAST('123' AS UNSIGNED);")
 ...
 box.execute("SELECT CAST('-123' AS UNSIGNED);")
 ---
-- error: 'Type mismatch: can not convert -123 to unsigned'
+- null
+- 'Type mismatch: can not convert -123 to unsigned'
 ...
 box.space.T1:drop()
 ---
diff --git a/test/sql/view.result b/test/sql/view.result
index 4f02032c7..d845df839 100644
--- a/test/sql/view.result
+++ b/test/sql/view.result
@@ -22,7 +22,8 @@ box.execute("CREATE VIEW v1 AS SELECT a+b FROM t1;");
 -- View can't have any indexes.
 box.execute("CREATE INDEX i1 on v1(a);");
 ---
-- error: 'Can''t create or modify index ''I1'' in space ''V1'': views can not be indexed'
+- null
+- 'Can''t create or modify index ''I1'' in space ''V1'': views can not be indexed'
 ...
 v1 = box.space.V1;
 ---
@@ -78,8 +79,8 @@ box.schema.create_space('view', {view = true})
 -- Space referenced by a view can't be renamed.
 box.execute("ALTER TABLE t1 RENAME TO new_name;")
 ---
-- error: 'Can''t modify space ''T1'': can not rename space which is referenced by
-    view'
+- null
+- 'Can''t modify space ''T1'': can not rename space which is referenced by view'
 ...
 -- View can be created via straight insertion into _space.
 sp = box.schema.create_space('test');
@@ -148,7 +149,8 @@ box.execute("CREATE VIEW v2 AS SELECT * FROM t2;");
 ...
 box.execute("DROP TABLE t2;");
 ---
-- error: 'Can''t drop space ''T2'': other views depend on this space'
+- null
+- 'Can''t drop space ''T2'': other views depend on this space'
 ...
 sp = box.space._space:get{box.space.T2.id};
 ---
@@ -158,7 +160,8 @@ sp = box.space._space:replace(sp);
 ...
 box.execute("DROP TABLE t2;");
 ---
-- error: 'Can''t drop space ''T2'': other views depend on this space'
+- null
+- 'Can''t drop space ''T2'': other views depend on this space'
 ...
 box.execute("DROP VIEW v2;");
 ---
@@ -216,7 +219,8 @@ box.execute("CREATE VIEW bv (wombat) AS VALUES ((SELECT 'k' FROM b));")
 ...
 box.execute("DROP TABLE b;")
 ---
-- error: 'Can''t drop space ''B'': other views depend on this space'
+- null
+- 'Can''t drop space ''B'': other views depend on this space'
 ...
 box.execute("DROP VIEW bv;")
 ---
@@ -240,7 +244,8 @@ box.execute("CREATE VIEW bcv AS SELECT * FROM b WHERE s1 IN (SELECT * FROM c);")
 ...
 box.execute("DROP TABLE c;")
 ---
-- error: 'Can''t drop space ''C'': other views depend on this space'
+- null
+- 'Can''t drop space ''C'': other views depend on this space'
 ...
 box.execute("DROP VIEW bcv;")
 ---
@@ -260,7 +265,8 @@ box.execute("CREATE VIEW bcv(x, y) AS VALUES((SELECT 'k' FROM b), (VALUES((SELEC
 ...
 box.execute("DROP TABLE c;")
 ---
-- error: 'Can''t drop space ''C'': other views depend on this space'
+- null
+- 'Can''t drop space ''C'': other views depend on this space'
 ...
 box.space.BCV:drop()
 ---
@@ -291,7 +297,8 @@ box.execute("CREATE VIEW v2 AS SELECT * FROM t2;")
 test_run:cmd('restart server default')
 box.execute("DROP TABLE t2;")
 ---
-- error: 'Can''t drop space ''T2'': other views depend on this space'
+- null
+- 'Can''t drop space ''T2'': other views depend on this space'
 ...
 box.execute("SELECT * FROM v2;")
 ---

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 17:00         ` Vladislav Shpilevoy
  2019-07-31 19:33           ` Konstantin Osipov
@ 2019-08-01  8:35           ` Alexander Turenko
  1 sibling, 0 replies; 17+ messages in thread
From: Alexander Turenko @ 2019-08-01  8:35 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: Imeev Mergen, tarantool-patches, kostja

On Wed, Jul 31, 2019 at 07:00:44PM +0200, Vladislav Shpilevoy wrote:
> 
> 
> On 31/07/2019 18:20, Imeev Mergen wrote:
> > 
> > On 7/31/19 6:40 PM, Vladislav Shpilevoy wrote:
> >>
> >> On 31/07/2019 17:23, Alexander Turenko wrote:
> >>>> +/**
> >>>> + * Return nil as the first return value and an error as the
> >>>> + * second. The error is received using box_error_last().
> >>>> + *
> >>>> + * @param L Lua stack.
> >>>> + */
> >>>> +LUA_API int
> >>>> +luaT_return_error(lua_State *L);
> >>> Maybe let the name be a bit more explicit, say,
> >>> luaT_push_conventional_error(struct lua_State *L)?
> >>>
> >> Please, no. You work too much with Java. The name
> >> is too long. Maybe luaT_push_nil_err()?
> > I thought that luaT_error() throws an error, and this one returns
> > it. So I called it luaT_return_error(). Should I change the name
> > to luaT_push_nil_err()?
> > 
> 
> For me 'return' was ok, but seems it is not ok for Kostja and
> Alexander. Lets wait.

We already have luaT_pusherror(). 'return' term triggers me here,
because we would use two terms for the same action.

luaT_push_nil_and_error() is okay for me: it is self-explanatory and
does not introduce a new term for an existing thing.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 17:15   ` Vladislav Shpilevoy
  2019-07-31 22:16     ` Mergen Imeev
@ 2019-08-01  8:59     ` Mergen Imeev
  1 sibling, 0 replies; 17+ messages in thread
From: Mergen Imeev @ 2019-08-01  8:59 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches, kostja

Hi! Thank you for review. I made changes you mentioned and
renamed function to luaT_push_nil_and_error().

Also, I noted that in function lbox_fio_cwd() before this
patch something was not right. Diff:

@@ -650,20 +622,12 @@ lbox_fio_cwd(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
-
-
-	if (getcwd(buf, PATH_MAX)) {
-		lua_pushstring(L, buf);
-		lua_remove(L, -2);
-	} else {
-		lbox_fio_pushsyserror(L);
-		lua_pushnil(L);
-		return 2;
+		return lbox_fio_pushsyserror(L);
 	}
+	if (getcwd(buf, PATH_MAX) == NULL)
+		return lbox_fio_pushsyserror(L);
+	lua_pushstring(L, buf);
+	lua_remove(L, -2);
 	return 1;
 }

As you can see, in the first case nil was the first and
error was the second, but it wasn't so in the other case.
I think this was a bug.

My answer and new patch below.

On Wed, Jul 31, 2019 at 07:15:13PM +0200, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patch!
>
>> diff --git a/src/lua/fio.c b/src/lua/fio.c
>> index 55fa667..cb7e31e 100644
>> --- a/src/lua/fio.c
>> +++ b/src/lua/fio.c
>> @@ -47,11 +47,9 @@
>>  #include "lua/utils.h"
>>  #include "coio_file.h"
>>  
>> -static inline void
>> -lbox_fio_pushsyserror(struct lua_State *L)
>> -{
>> -	diag_set(SystemError, "fio: %s", strerror(errno));
>> -	luaT_pusherror(L, diag_get()->last);
>> +#define lbox_fio_pushsyserror(L) {				\
>> +	diag_set(SystemError, "fio: %s", strerror(errno));	\
>> +	return luaT_return_error(L);				\
>>  }
>
> Please, don't return here. It makes the code below
> confusing, when you call 'pushsyserror, pushinteger', and
> return 1. Make this macro return value of the last block,
> and surround it with '()' or with 'do {...} while(false)'
> to be force ';' after it, and be able to use it in
> 'if ... else ...' constructions. It is a standard practice.
>
> #define lbox_fio_pushsyserror(L) ({				\
> 	diag_set(SystemError, "fio: %s", strerror(errno));	\
> 	luaT_return_error(L);					\
> })
>
> and use 'return lbox_fio_pushsyserror(L);' in the code
> below.
>
Thank you! Fixed.


New patch:

From 06f6a8f4e103e759233823ea508f9764a371f026 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Wed, 31 Jul 2019 12:43:58 +0300
Subject: [PATCH] lua: new function luaT_push_nil_and_error()

Currently, if we have to return errors using the format
'return nil, error', we must do it manually. Since this error
return method is described in our Lua coding style, it makes sense
to create a function that will return an error in this format.
This patch creates mentioned function.

Needed for #4390

diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index c0ac4917b..b9495e7a6 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -395,14 +395,10 @@ lbox_session_push(struct lua_State *L)
 	}
 	struct port port;
 	port_lua_create(&port, L);
-	if (session_push(session, sync, &port) != 0) {
-		lua_pushnil(L);
-		luaT_pusherror(L, box_error_last());
-		return 2;
-	} else {
-		lua_pushboolean(L, true);
-		return 1;
-	}
+	if (session_push(session, sync, &port) != 0)
+		return luaT_push_nil_and_error(L);
+	lua_pushboolean(L, true);
+	return 1;
 }
 
 /**
diff --git a/src/lua/error.c b/src/lua/error.c
index fca87f9d6..d82e78dc4 100644
--- a/src/lua/error.c
+++ b/src/lua/error.c
@@ -104,6 +104,16 @@ luaT_error(lua_State *L)
 	return 0;
 }
 
+int
+luaT_push_nil_and_error(lua_State *L)
+{
+	struct error *e = diag_last_error(&fiber()->diag);
+	assert(e != NULL);
+	lua_pushnil(L);
+	luaT_pusherror(L, e);
+	return 2;
+}
+
 void
 tarantool_lua_error_init(struct lua_State *L)
 {
diff --git a/src/lua/error.h b/src/lua/error.h
index 67a43da86..64fa5eba3 100644
--- a/src/lua/error.h
+++ b/src/lua/error.h
@@ -49,6 +49,15 @@ struct error;
 LUA_API int
 luaT_error(lua_State *L);
 
+/**
+ * Return nil as the first return value and an error as the
+ * second. The error is received using box_error_last().
+ *
+ * @param L Lua stack.
+ */
+LUA_API int
+luaT_push_nil_and_error(lua_State *L);
+
 void
 luaT_pusherror(struct lua_State *L, struct error *e);
 /** \endcond public */
diff --git a/src/lua/fio.c b/src/lua/fio.c
index 55fa66762..e5d3458fd 100644
--- a/src/lua/fio.c
+++ b/src/lua/fio.c
@@ -47,12 +47,10 @@
 #include "lua/utils.h"
 #include "coio_file.h"
 
-static inline void
-lbox_fio_pushsyserror(struct lua_State *L)
-{
-	diag_set(SystemError, "fio: %s", strerror(errno));
-	luaT_pusherror(L, diag_get()->last);
-}
+#define lbox_fio_pushsyserror(L) ({				\
+	diag_set(SystemError, "fio: %s", strerror(errno));	\
+	luaT_push_nil_and_error(L);					\
+})
 
 static int
 lbox_fio_open(struct lua_State *L)
@@ -69,11 +67,8 @@ usage:
 	int mode = lua_tointeger(L, 3);
 
 	int fh = coio_file_open(pathname, flags, mode);
-	if (fh < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (fh < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, fh);
 	return 1;
 }
@@ -90,11 +85,8 @@ lbox_fio_pwrite(struct lua_State *L)
 	size_t offset = lua_tonumber(L, 4);
 
 	int res = coio_pwrite(fh, buf, len, offset);
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -115,11 +107,8 @@ lbox_fio_pread(struct lua_State *L)
 
 	int res = coio_pread(fh, buf, len, offset);
 
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -129,7 +118,10 @@ lbox_fio_pushbool(struct lua_State *L, bool res)
 {
 	lua_pushboolean(L, res);
 	if (!res) {
-		lbox_fio_pushsyserror(L);
+		diag_set(SystemError, "fio: %s", strerror(errno));
+		struct error *e = diag_last_error(diag_get());
+		assert(e != NULL);
+		luaT_pusherror(L, e);
 		return 2;
 	}
 	return 1;
@@ -211,11 +203,8 @@ lbox_fio_write(struct lua_State *L)
 	size_t len = lua_tonumber(L, 3);
 
 	int res = coio_write(fh, buf, len);
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -298,11 +287,8 @@ lbox_fio_read(struct lua_State *L)
 
 	int res = coio_read(fh, buf, len);
 
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushinteger(L, res);
 	return 1;
 }
@@ -371,11 +357,8 @@ DEF_STAT_METHOD(is_sock, S_ISSOCK);
 static int
 lbox_fio_pushstat(struct lua_State *L, int res, const struct stat *stat)
 {
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_newtable(L);
 
 	PUSHTABLE("dev", lua_pushinteger, stat->st_dev);
@@ -518,11 +501,8 @@ lbox_fio_listdir(struct lua_State *L)
 	}
 	pathname = lua_tostring(L, 1);
 	char *buf;
-	if (coio_readdir(pathname, &buf) < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (coio_readdir(pathname, &buf) < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushstring(L, buf);
 	free(buf);
 	return 1;
@@ -613,11 +593,8 @@ usage:
 		goto usage;
 	char *path = (char *)lua_newuserdata(L, PATH_MAX);
 	int res = coio_readlink(pathname, path, PATH_MAX);
-	if (res < 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (res < 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushlstring(L, path, res);
 	lua_remove(L, -2);
 	return 1;
@@ -629,16 +606,11 @@ lbox_fio_tempdir(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
+		return lbox_fio_pushsyserror(L);
 	}
 
-	if (coio_tempdir(buf, PATH_MAX) != 0) {
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
+	if (coio_tempdir(buf, PATH_MAX) != 0)
+		return lbox_fio_pushsyserror(L);
 	lua_pushstring(L, buf);
 	lua_remove(L, -2);
 	return 1;
@@ -650,20 +622,12 @@ lbox_fio_cwd(struct lua_State *L)
 	char *buf = (char *)lua_newuserdata(L, PATH_MAX);
 	if (!buf) {
 		errno = ENOMEM;
-		lua_pushnil(L);
-		lbox_fio_pushsyserror(L);
-		return 2;
-	}
-
-
-	if (getcwd(buf, PATH_MAX)) {
-		lua_pushstring(L, buf);
-		lua_remove(L, -2);
-	} else {
-		lbox_fio_pushsyserror(L);
-		lua_pushnil(L);
-		return 2;
+		return lbox_fio_pushsyserror(L);
 	}
+	if (getcwd(buf, PATH_MAX) == NULL)
+		return lbox_fio_pushsyserror(L);
+	lua_pushstring(L, buf);
+	lua_remove(L, -2);
 	return 1;
 }
 
diff --git a/src/lua/swim.c b/src/lua/swim.c
index 26646f41f..ae916bf78 100644
--- a/src/lua/swim.c
+++ b/src/lua/swim.c
@@ -69,11 +69,10 @@ lua_swim_new(struct lua_State *L)
 {
 	uint64_t generation = luaL_checkuint64(L, 1);
 	struct swim *s = swim_new(generation);
+	if (s == NULL)
+		return luaT_push_nil_and_error(L);
 	*(struct swim **) luaL_pushcdata(L, ctid_swim_ptr) = s;
-	if (s != NULL)
-		return 1;
-	luaT_pusherror(L, diag_last_error(diag_get()));
-	return 2;
+	return 1;
 }
 
 /**

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 1/2] lua: new function luaT_return_error()
  2019-07-31 22:16     ` Mergen Imeev
@ 2019-08-01 20:03       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 17+ messages in thread
From: Vladislav Shpilevoy @ 2019-08-01 20:03 UTC (permalink / raw)
  To: tarantool-patches, Mergen Imeev, Kirill Yukhin

Hi! Thanks for the fixes!

I've force pushed this:

===========================================================================
diff --git a/src/lua/fio.c b/src/lua/fio.c
index e5d3458fd..7437cc0c6 100644
--- a/src/lua/fio.c
+++ b/src/lua/fio.c
@@ -49,7 +49,7 @@
 
 #define lbox_fio_pushsyserror(L) ({				\
 	diag_set(SystemError, "fio: %s", strerror(errno));	\
-	luaT_push_nil_and_error(L);					\
+	luaT_push_nil_and_error(L);				\
 })
 
 static int
===========================================================================

Now the patchset LGTM. Kirill, please, push.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [tarantool-patches] Re: [PATCH v2 0/2] sql: rework error handling in box.execute()
  2019-07-31 10:32 [tarantool-patches] [PATCH v2 0/2] sql: rework error handling in box.execute() imeevma
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error() imeevma
  2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 2/2] sql: rework error handling in box.execute() imeevma
@ 2019-08-02  5:39 ` Kirill Yukhin
  2 siblings, 0 replies; 17+ messages in thread
From: Kirill Yukhin @ 2019-08-02  5:39 UTC (permalink / raw)
  To: tarantool-patches; +Cc: v.shpilevoy, kostja

Hello,

On 31 Jul 13:32, imeevma@tarantool.org wrote:
> This patch-set reworks the error handling of box.execute(). After
> this patch-set, box.execute() will return nil as the first return
> value, and error as the second.
> 
> https://github.com/tarantool/tarantool/issues/4390
> https://github.com/tarantool/tarantool/tree/imeevma/gh-4390-box_execute-should-not-throw
> 
> Changes in v2:
>  - Added function, that pushes nil and error in Lua stack.
> 
> Mergen Imeev (2):
>   lua: new function luaT_return_error()
>   sql: rework error handling in box.execute()

I've checked the patchset into master.

--
Regards, Kirill Yukhin

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2019-08-02  5:39 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-31 10:32 [tarantool-patches] [PATCH v2 0/2] sql: rework error handling in box.execute() imeevma
2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 1/2] lua: new function luaT_return_error() imeevma
2019-07-31 15:23   ` [tarantool-patches] " Alexander Turenko
2019-07-31 15:39     ` Konstantin Osipov
2019-07-31 15:40     ` Vladislav Shpilevoy
2019-07-31 16:20       ` Imeev Mergen
2019-07-31 17:00         ` Vladislav Shpilevoy
2019-07-31 19:33           ` Konstantin Osipov
2019-08-01  8:35           ` Alexander Turenko
2019-07-31 19:32         ` Konstantin Osipov
2019-07-31 17:15   ` Vladislav Shpilevoy
2019-07-31 22:16     ` Mergen Imeev
2019-08-01 20:03       ` Vladislav Shpilevoy
2019-08-01  8:59     ` Mergen Imeev
2019-07-31 10:32 ` [tarantool-patches] [PATCH v2 2/2] sql: rework error handling in box.execute() imeevma
2019-07-31 22:23   ` [tarantool-patches] " Mergen Imeev
2019-08-02  5:39 ` [tarantool-patches] Re: [PATCH v2 0/2] " Kirill Yukhin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox