Tarantool development patches archive
 help / color / mirror / Atom feed
* [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL
@ 2019-02-25 17:14 imeevma
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error imeevma
                   ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: imeevma @ 2019-02-25 17:14 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

The goal of this patch-set is to rework all SQL errors and make
Tarantool ones from them. Currently this patch-set contains five
pathes that rewords all parser errors. Only part of these errors
were completely reworked.

Difference from last version:
 - Patch-set was completely reworked.
 - Error "empty request" will be mentioned after issue 3965 will
   be closed due to refactoring nature of the issue 3965.

https://github.com/tarantool/tarantool/issues/3965
https://github.com/tarantool/tarantool/tree/imeevma/gh-3965-use-diag_set-to-describe-error

Mergen Imeev (5):
  sql: remove "syntax error after column name" error
  sql: rework syntax errors
  sql: save SQL parser errors in diag_set()
  sql: remove file zErrMsg of struct Parse
  sql: remove field nErr of struct Parse

 src/box/errcode.h                          |  8 +++
 src/box/sql.c                              | 13 ++---
 src/box/sql/alter.c                        |  1 -
 src/box/sql/analyze.c                      |  2 -
 src/box/sql/build.c                        | 79 +++++++++++-------------------
 src/box/sql/callback.c                     |  1 -
 src/box/sql/delete.c                       | 28 ++++-------
 src/box/sql/expr.c                         | 26 +++++-----
 src/box/sql/insert.c                       |  4 +-
 src/box/sql/parse.y                        | 63 ++++++++++++------------
 src/box/sql/pragma.c                       |  5 +-
 src/box/sql/prepare.c                      | 12 ++---
 src/box/sql/resolve.c                      | 22 ++++-----
 src/box/sql/select.c                       | 37 +++++++-------
 src/box/sql/sqlInt.h                       | 12 +----
 src/box/sql/tokenize.c                     | 46 +++++------------
 src/box/sql/trigger.c                      | 27 ++--------
 src/box/sql/update.c                       |  4 +-
 src/box/sql/util.c                         | 14 ++----
 src/box/sql/where.c                        |  3 +-
 src/box/sql/wherecode.c                    |  5 +-
 test/box/misc.result                       |  7 +++
 test/sql-tap/alter2.test.lua               |  4 +-
 test/sql-tap/blob.test.lua                 | 20 ++++----
 test/sql-tap/check.test.lua                | 16 +++---
 test/sql-tap/colname.test.lua              |  2 +-
 test/sql-tap/count.test.lua                |  2 +-
 test/sql-tap/default.test.lua              |  4 +-
 test/sql-tap/e_select1.test.lua            | 18 +++----
 test/sql-tap/gh-2367-pragma.test.lua       |  4 +-
 test/sql-tap/gh2168-temp-tables.test.lua   |  4 +-
 test/sql-tap/identifier_case.test.lua      |  2 +-
 test/sql-tap/index-info.test.lua           |  2 +-
 test/sql-tap/index1.test.lua               |  2 +-
 test/sql-tap/index7.test.lua               |  2 +-
 test/sql-tap/join.test.lua                 |  2 +-
 test/sql-tap/keyword1.test.lua             |  2 +-
 test/sql-tap/misc1.test.lua                |  8 +--
 test/sql-tap/misc5.test.lua                |  6 +--
 test/sql-tap/null.test.lua                 |  8 +--
 test/sql-tap/select1.test.lua              | 20 ++++----
 test/sql-tap/select3.test.lua              |  6 +--
 test/sql-tap/select5.test.lua              | 10 ++--
 test/sql-tap/start-transaction.test.lua    | 14 +++---
 test/sql-tap/table.test.lua                | 10 ++--
 test/sql-tap/tkt3935.test.lua              | 14 +++---
 test/sql-tap/tokenize.test.lua             | 26 +++++-----
 test/sql-tap/trigger1.test.lua             | 14 +++---
 test/sql-tap/view.test.lua                 |  4 +-
 test/sql-tap/with1.test.lua                |  6 +--
 test/sql-tap/with2.test.lua                | 18 +++----
 test/sql/checks.result                     | 12 ++---
 test/sql/collation.result                  | 12 ++---
 test/sql/delete.result                     |  5 +-
 test/sql/foreign-keys.result               | 10 ++--
 test/sql/gh-3888-values-blob-assert.result |  8 +--
 test/sql/iproto.result                     | 10 ++--
 test/sql/misc.result                       | 14 +++---
 test/sql/on-conflict.result                | 19 ++++---
 test/sql/triggers.result                   |  4 +-
 test/sql/types.result                      | 13 +++--
 61 files changed, 340 insertions(+), 436 deletions(-)

-- 
2.7.4

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

* [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error
  2019-02-25 17:14 [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL imeevma
@ 2019-02-25 17:14 ` imeevma
  2019-02-25 19:34   ` [tarantool-patches] " n.pettik
  2019-02-27 11:32   ` Kirill Yukhin
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 2/5] sql: rework syntax errors imeevma
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 21+ messages in thread
From: imeevma @ 2019-02-25 17:14 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

Error "syntax error after column name" does not make any sense.
Let's remove it.

Part of #3965
---
 src/box/sql/parse.y        | 22 +++++-----------------
 test/sql-tap/view.test.lua |  2 +-
 2 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 32db685..a5ac220 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -1247,17 +1247,9 @@ uniqueflag(A) ::= .        {A = SQL_INDEX_TYPE_NON_UNIQUE;}
   static ExprList *parserAddExprIdListTerm(
     Parse *pParse,
     ExprList *pPrior,
-    Token *pIdToken,
-    int hasCollate,
-    int sortOrder
+    Token *pIdToken
   ){
     ExprList *p = sql_expr_list_append(pParse->db, pPrior, NULL);
-    if( (hasCollate || sortOrder != SORT_ORDER_UNDEF)
-        && pParse->db->init.busy==0
-    ){
-      sqlErrorMsg(pParse, "syntax error after column name \"%.*s\"",
-                         pIdToken->n, pIdToken->z);
-    }
     sqlExprListSetName(pParse, p, pIdToken, 1);
     return p;
   }
@@ -1265,17 +1257,13 @@ uniqueflag(A) ::= .        {A = SQL_INDEX_TYPE_NON_UNIQUE;}
 
 eidlist_opt(A) ::= .                         {A = 0;}
 eidlist_opt(A) ::= LP eidlist(X) RP.         {A = X;}
-eidlist(A) ::= eidlist(A) COMMA nm(Y) collate(C) sortorder(Z).  {
-  A = parserAddExprIdListTerm(pParse, A, &Y, C, Z);
+eidlist(A) ::= eidlist(A) COMMA nm(Y).  {
+  A = parserAddExprIdListTerm(pParse, A, &Y);
 }
-eidlist(A) ::= nm(Y) collate(C) sortorder(Z). {
-  A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z); /*A-overwrites-Y*/
+eidlist(A) ::= nm(Y). {
+  A = parserAddExprIdListTerm(pParse, 0, &Y); /*A-overwrites-Y*/
 }
 
-%type collate {int}
-collate(C) ::= .              {C = 0;}
-collate(C) ::= COLLATE id.   {C = 1;}
-
 
 ///////////////////////////// The DROP INDEX command /////////////////////////
 //
diff --git a/test/sql-tap/view.test.lua b/test/sql-tap/view.test.lua
index 49916d6..c99a0a5 100755
--- a/test/sql-tap/view.test.lua
+++ b/test/sql-tap/view.test.lua
@@ -293,7 +293,7 @@ test:do_catchsql_test(
         CREATE VIEW v1err(x,y DESC,z) AS SELECT a, b+c, c-b FROM t1;
     ]], {
         -- <view-3.3.4>
-        1, [[syntax error after column name "y"]]
+        1, [[keyword "DESC" is reserved]]
         -- </view-3.3.4>
     })
 
-- 
2.7.4

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

* [tarantool-patches] [PATCH v2 2/5] sql: rework syntax errors
  2019-02-25 17:14 [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL imeevma
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error imeevma
@ 2019-02-25 17:14 ` imeevma
  2019-02-25 20:02   ` [tarantool-patches] " n.pettik
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 3/5] sql: save SQL parser errors in diag_set() imeevma
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: imeevma @ 2019-02-25 17:14 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

This patch reworks SQL syntax errors. After this patch, these
error will be set as Tarantool errors.

Part of #3965
---
 src/box/errcode.h                          |  7 +++++
 src/box/sql/build.c                        |  6 ++---
 src/box/sql/parse.y                        | 41 ++++++++++++++++++------------
 src/box/sql/select.c                       | 11 ++++----
 src/box/sql/tokenize.c                     |  7 ++---
 test/box/misc.result                       |  6 +++++
 test/sql-tap/alter2.test.lua               |  4 +--
 test/sql-tap/blob.test.lua                 | 20 +++++++--------
 test/sql-tap/check.test.lua                | 10 ++++----
 test/sql-tap/colname.test.lua              |  2 +-
 test/sql-tap/count.test.lua                |  2 +-
 test/sql-tap/default.test.lua              |  4 +--
 test/sql-tap/e_select1.test.lua            | 18 ++++++-------
 test/sql-tap/gh-2367-pragma.test.lua       |  4 +--
 test/sql-tap/gh2168-temp-tables.test.lua   |  4 +--
 test/sql-tap/identifier_case.test.lua      |  2 +-
 test/sql-tap/index-info.test.lua           |  2 +-
 test/sql-tap/index1.test.lua               |  2 +-
 test/sql-tap/index7.test.lua               |  2 +-
 test/sql-tap/join.test.lua                 |  2 +-
 test/sql-tap/keyword1.test.lua             |  2 +-
 test/sql-tap/misc1.test.lua                |  8 +++---
 test/sql-tap/misc5.test.lua                |  6 ++---
 test/sql-tap/null.test.lua                 |  8 +++---
 test/sql-tap/select1.test.lua              | 20 +++++++--------
 test/sql-tap/select3.test.lua              |  4 +--
 test/sql-tap/start-transaction.test.lua    | 14 +++++-----
 test/sql-tap/table.test.lua                | 10 ++++----
 test/sql-tap/tkt3935.test.lua              | 14 +++++-----
 test/sql-tap/tokenize.test.lua             | 26 +++++++++----------
 test/sql-tap/trigger1.test.lua             | 14 +++++-----
 test/sql-tap/view.test.lua                 |  4 +--
 test/sql-tap/with1.test.lua                |  6 ++---
 test/sql-tap/with2.test.lua                | 18 ++++++-------
 test/sql/checks.result                     |  2 +-
 test/sql/collation.result                  | 12 ++++-----
 test/sql/foreign-keys.result               | 10 +++++---
 test/sql/gh-3888-values-blob-assert.result |  8 +++---
 test/sql/iproto.result                     | 10 ++++----
 test/sql/misc.result                       | 14 +++++-----
 test/sql/on-conflict.result                | 16 ++++++------
 test/sql/types.result                      | 13 ++++++----
 42 files changed, 213 insertions(+), 182 deletions(-)

diff --git a/src/box/errcode.h b/src/box/errcode.h
index a1fcf01..6546b2f 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -231,6 +231,13 @@ struct errcode_record {
 	/*176 */_(ER_SQL_CANT_RESOLVE_FIELD,	"Can’t resolve field '%s'") \
 	/*177 */_(ER_INDEX_EXISTS_IN_SPACE,	"Index '%s' already exists in space '%s'") \
 	/*178 */_(ER_INCONSISTENT_TYPES,	"Inconsistent types: expected %s got %s") \
+	/*179 */_(ER_SQL_SYNTAX,		"Syntax error in %s: %s") \
+	/*180 */_(ER_SQL_STACK_OVERFLOW,	"Failed to parse SQL statement: parser stack limit reached") \
+	/*181 */_(ER_SQL_SELECT_WILDCARD,	"Failed to expand '*' in SELECT statement without FROM clause") \
+	/*182 */_(ER_SQL_STATEMENT_EMPTY,	"Failed to execute an empty SQL statement") \
+	/*183 */_(ER_SQL_KEYWORD_IS_RESERVED,	"Keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
+	/*184 */_(ER_SQL_SYNTAX_NEAR,		"Unrecognized syntax near '%.*s'") \
+	/*185 */_(ER_SQL_UNKNOWN_TOKEN,		"Syntax error: unrecognized token: '%.*s'") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index e9851d9..f112c9f 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -2823,9 +2823,9 @@ sqlSrcListAppendFromTerm(Parse * pParse,	/* Parsing context */
 	struct SrcList_item *pItem;
 	sql *db = pParse->db;
 	if (!p && (pOn || pUsing)) {
-		sqlErrorMsg(pParse, "a JOIN clause is required before %s",
-				(pOn ? "ON" : "USING")
-		    );
+		diag_set(ClientError, ER_SQL_SYNTAX, "FROM clause",
+			 "a JOIN clause is required before ON and USING");
+		sql_parser_error(pParse);
 		goto append_from_error;
 	}
 	p = sqlSrcListAppend(db, p, pTable);
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index a5ac220..67a7a57 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -33,13 +33,16 @@
   UNUSED_PARAMETER(yymajor);  /* Silence some compiler warnings */
   assert( TOKEN.z[0] );  /* The tokenizer always gives us a token */
   if (yypParser->is_fallback_failed && TOKEN.isReserved) {
-    sqlErrorMsg(pParse, "keyword \"%T\" is reserved", &TOKEN);
+    diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, TOKEN.n, TOKEN.z,
+             TOKEN.n, TOKEN.z);
   } else {
-    sqlErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+    diag_set(ClientError, ER_SQL_SYNTAX_NEAR, TOKEN.n, TOKEN.z);
   }
+  sql_parser_error(pParse);
 }
 %stack_overflow {
-  sqlErrorMsg(pParse, "parser stack overflow");
+  diag_set(ClientError, ER_SQL_STACK_OVERFLOW);
+  sql_parser_error(pParse);
 }
 
 // The name of the generated procedure that implements the parser
@@ -114,7 +117,8 @@ ecmd ::= explain cmdx SEMI. {
 		sql_finish_coding(pParse);
 }
 ecmd ::= SEMI. {
-  sqlErrorMsg(pParse, "syntax error: empty request");
+  diag_set(ClientError, ER_SQL_STATEMENT_EMPTY);
+  sql_parser_error(pParse);
 }
 explain ::= .
 explain ::= EXPLAIN.              { pParse->explain = 1; }
@@ -227,7 +231,8 @@ columnname(A) ::= nm(A) typedef(Y). {sqlAddColumn(pParse,&A,&Y);}
 %type nm {Token}
 nm(A) ::= id(A). {
   if(A.isReserved) {
-    sqlErrorMsg(pParse, "keyword \"%T\" is reserved", &A);
+    diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, A.n, A.z, A.n, A.z);
+    sql_parser_error(pParse);
   }
 }
 
@@ -897,14 +902,17 @@ expr(A) ::= VARIABLE(X).     {
   } else if (!(X.z[0]=='#' && sqlIsdigit(X.z[1]))) {
     u32 n = X.n;
     spanExpr(&A, pParse, TK_VARIABLE, X);
-    if (A.pExpr->u.zToken[0] == '?' && n > 1)
-        sqlErrorMsg(pParse, "near \"%T\": syntax error", &t);
-    else
-        sqlExprAssignVarNumber(pParse, A.pExpr, n);
+    if (A.pExpr->u.zToken[0] == '?' && n > 1) {
+      diag_set(ClientError, ER_SQL_SYNTAX_NEAR, t.n, t.z);
+      sql_parser_error(pParse);
+    } else {
+      sqlExprAssignVarNumber(pParse, A.pExpr, n);
+    }
   }else{
     assert( t.n>=2 );
     spanSet(&A, &t, &t);
-    sqlErrorMsg(pParse, "near \"%T\": syntax error", &t);
+    diag_set(ClientError, ER_SQL_SYNTAX_NEAR, t.n, t.z);
+    sql_parser_error(pParse);
     A.pExpr = NULL;
   }
 }
@@ -1374,14 +1382,15 @@ trnm(A) ::= nm DOT nm(X). {
 //
 tridxby ::= .
 tridxby ::= INDEXED BY nm. {
-  sqlErrorMsg(pParse,
-        "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
-        "within triggers");
+  diag_set(ClientError, ER_SQL_SYNTAX, "trigger body", "the INDEXED BY clause "\
+           "is not allowed on UPDATE or DELETE statements within triggers");
+  sql_parser_error(pParse);
 }
 tridxby ::= NOT INDEXED. {
-  sqlErrorMsg(pParse,
-        "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
-        "within triggers");
+  diag_set(ClientError, ER_SQL_SYNTAX, "trigger body", "the NOT INDEXED "\
+           "clause is not allowed on UPDATE or DELETE statements within "\
+           "triggers");
+  sql_parser_error(pParse);
 }
 
 
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 6a465a6..7eea90e 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -2092,8 +2092,9 @@ computeLimitRegisters(Parse * pParse, Select * p, int iBreak)
 		if((p->pLimit->flags & EP_Collate) != 0 ||
 		   (p->pOffset != NULL &&
 		   (p->pOffset->flags & EP_Collate) != 0)) {
-			sqlErrorMsg(pParse, "near \"COLLATE\": "\
-						"syntax error");
+			diag_set(ClientError, ER_SQL_SYNTAX_NEAR,
+				 sizeof("COLLATE"), "COLLATE");
+			sql_parser_error(pParse);
 			return;
 		}
 		p->iLimit = iLimit = ++pParse->nMem;
@@ -5050,11 +5051,11 @@ selectExpander(Walker * pWalker, Select * p)
 						diag_set(ClientError,
 							 ER_NO_SUCH_SPACE,
 							 zTName);
-						sql_parser_error(pParse);
 					} else {
-						sqlErrorMsg(pParse,
-								"no tables specified");
+						diag_set(ClientError,
+							 ER_SQL_SELECT_WILDCARD);
 					}
+					sql_parser_error(pParse);
 				}
 			}
 		}
diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
index 0de0406..44a7bb9 100644
--- a/src/box/sql/tokenize.c
+++ b/src/box/sql/tokenize.c
@@ -506,9 +506,10 @@ sqlRunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
 				break;
 			}
 			if (tokenType == TK_ILLEGAL) {
-				sqlErrorMsg(pParse,
-						"unrecognized token: \"%T\"",
-						&pParse->sLastToken);
+				diag_set(ClientError, ER_SQL_UNKNOWN_TOKEN,
+					 pParse->sLastToken.n,
+					 pParse->sLastToken.z);
+				sql_parser_error(pParse);
 				break;
 			}
 		} else {
diff --git a/test/box/misc.result b/test/box/misc.result
index d9f5dd5..a1c94bf 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -508,6 +508,12 @@ t;
   176: box.error.SQL_CANT_RESOLVE_FIELD
   177: box.error.INDEX_EXISTS_IN_SPACE
   178: box.error.INCONSISTENT_TYPES
+  179: box.error.SQL_SYNTAX
+  180: box.error.SQL_STACK_OVERFLOW
+  181: box.error.SQL_SELECT_WILDCARD
+  182: box.error.SQL_STATEMENT_EMPTY
+  184: box.error.SQL_SYNTAX_NEAR
+  185: box.error.SQL_UNKNOWN_TOKEN
 ...
 test_run:cmd("setopt delimiter ''");
 ---
diff --git a/test/sql-tap/alter2.test.lua b/test/sql-tap/alter2.test.lua
index e219a36..ef57955 100755
--- a/test/sql-tap/alter2.test.lua
+++ b/test/sql-tap/alter2.test.lua
@@ -223,7 +223,7 @@ test:do_catchsql_test(
         ALTER TABLE child ADD CONSTRAINT fk FOREIGN KEY REFERENCES child(id);
     ]], {
         -- <alter2-4.1>
-        1, "near \"REFERENCES\": syntax error"
+        1, "Unrecognized syntax near 'REFERENCES'"
         -- </alter2-4.1>
     })
 
@@ -233,7 +233,7 @@ test:do_catchsql_test(
         ALTER TABLE child ADD CONSTRAINT fk () FOREIGN KEY REFERENCES child(id);
     ]], {
         -- <alter2-4.1>
-        1, "near \"(\": syntax error"
+        1, "Unrecognized syntax near '('"
         -- </alter2-4.2>
     })
 
diff --git a/test/sql-tap/blob.test.lua b/test/sql-tap/blob.test.lua
index c7b328a..e2cc4d9 100755
--- a/test/sql-tap/blob.test.lua
+++ b/test/sql-tap/blob.test.lua
@@ -72,7 +72,7 @@ test:do_catchsql_test(
         SELECT X'01020k304', 100
     ]], {
         -- <blob-1.4>
-        1, [[unrecognized token: "X'01020k304'"]]
+        1, [[Syntax error: unrecognized token: 'X'01020k304'']]
         -- </blob-1.4>
     })
 
@@ -81,7 +81,7 @@ test:do_catchsql_test(
     [[
         SELECT X'01020, 100]], {
         -- <blob-1.5>
-        1, [[unrecognized token: "X'01020, 100"]]
+        1, [[Syntax error: unrecognized token: 'X'01020, 100']]
         -- </blob-1.5>
     })
 
@@ -91,7 +91,7 @@ test:do_catchsql_test(
         SELECT X'01020 100'
     ]], {
         -- <blob-1.6>
-        1, [[unrecognized token: "X'01020 100'"]]
+        1, [[Syntax error: unrecognized token: 'X'01020 100'']]
         -- </blob-1.6>
     })
 
@@ -101,7 +101,7 @@ test:do_catchsql_test(
         SELECT X'01001'
     ]], {
         -- <blob-1.7>
-        1, [[unrecognized token: "X'01001'"]]
+        1, [[Syntax error: unrecognized token: 'X'01001'']]
         -- </blob-1.7>
     })
 
@@ -111,7 +111,7 @@ test:do_catchsql_test(
         SELECT x'012/45'
     ]], {
         -- <blob-1.8>
-        1, [[unrecognized token: "x'012/45'"]]
+        1, [[Syntax error: unrecognized token: 'x'012/45'']]
         -- </blob-1.8>
     })
 
@@ -121,7 +121,7 @@ test:do_catchsql_test(
         SELECT x'012:45'
     ]], {
         -- <blob-1.9>
-        1, [[unrecognized token: "x'012:45'"]]
+        1, [[Syntax error: unrecognized token: 'x'012:45'']]
         -- </blob-1.9>
     })
 
@@ -131,7 +131,7 @@ test:do_catchsql_test(
         SELECT x'012@45'
     ]], {
         -- <blob-1.10>
-        1, [[unrecognized token: "x'012@45'"]]
+        1, [[Syntax error: unrecognized token: 'x'012@45'']]
         -- </blob-1.10>
     })
 
@@ -141,7 +141,7 @@ test:do_catchsql_test(
         SELECT x'012G45'
     ]], {
         -- <blob-1.11>
-        1, [[unrecognized token: "x'012G45'"]]
+        1, [[Syntax error: unrecognized token: 'x'012G45'']]
         -- </blob-1.11>
     })
 
@@ -151,7 +151,7 @@ test:do_catchsql_test(
         SELECT x'012`45'
     ]], {
         -- <blob-1.12>
-        1, [[unrecognized token: "x'012`45'"]]
+        1, [[Syntax error: unrecognized token: 'x'012`45'']]
         -- </blob-1.12>
     })
 
@@ -161,7 +161,7 @@ test:do_catchsql_test(
         SELECT x'012g45'
     ]], {
         -- <blob-1.13>
-        1, [[unrecognized token: "x'012g45'"]]
+        1, [[Syntax error: unrecognized token: 'x'012g45'']]
         -- </blob-1.13>
     })
 
diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua
index 2bb1b2e..f7d3ffe 100755
--- a/test/sql-tap/check.test.lua
+++ b/test/sql-tap/check.test.lua
@@ -281,7 +281,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-2.10>
-        1,"near \",\": syntax error"
+        1,"Unrecognized syntax near ','"
         -- </check-2.10>
     })
 
@@ -295,7 +295,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-2.10>
-        1,"near \",\": syntax error"
+        1,"Unrecognized syntax near ','"
         -- </check-2.10>
     })
 
@@ -781,7 +781,7 @@ test:do_catchsql_test(
         ON CONFLICT REPLACE)
     ]], {
         -- <9.1>
-        1, "keyword \"ON\" is reserved"
+        1, "Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
         -- </9.1>
     })
 
@@ -792,7 +792,7 @@ test:do_catchsql_test(
         ON CONFLICT ABORT)
     ]], {
         -- <9.2>
-        1, "keyword \"ON\" is reserved"
+        1, "Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
         -- </9.2>
     })
 
@@ -803,7 +803,7 @@ test:do_catchsql_test(
         ON CONFLICT ROLLBACK)
     ]], {
         -- <9.3>
-        1, "keyword \"ON\" is reserved"
+        1, "Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
         -- </9.3>
     })
 
diff --git a/test/sql-tap/colname.test.lua b/test/sql-tap/colname.test.lua
index b7dd2b7..db655a7 100755
--- a/test/sql-tap/colname.test.lua
+++ b/test/sql-tap/colname.test.lua
@@ -576,7 +576,7 @@ for i, val in ipairs(data) do
 end
 
 local data2 = {
-    {[['a']],{1, "/syntax error/"}}, -- because ' is delimiter for strings
+    {[['a']],{1, "/Unrecognized syntax/"}}, -- because ' is delimiter for strings
     {[[`a`]],{1, "/unrecognized token/"}}, -- because ` is undefined symbol
     {"[a]",{1, "/unrecognized token/"}} -- because [ is undefined symbol
 }
diff --git a/test/sql-tap/count.test.lua b/test/sql-tap/count.test.lua
index fbd60da..fb2d403 100755
--- a/test/sql-tap/count.test.lua
+++ b/test/sql-tap/count.test.lua
@@ -128,7 +128,7 @@ test:do_catchsql_test(
         SELECT count(DISTINCT *) FROM t2
     ]], {
         -- <count-2.2>
-        1, [[near "*": syntax error]]
+        1, [[Unrecognized syntax near '*']]
         -- </count-2.2>
     })
 
diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua
index e0dbb91..ec8928a 100755
--- a/test/sql-tap/default.test.lua
+++ b/test/sql-tap/default.test.lua
@@ -224,7 +224,7 @@ test:do_catchsql_test(
         CREATE TABLE t6(id INTEGER PRIMARY KEY, b TEXT DEFAULT id);
     ]], {
     -- <default-5.2>
-    1, "near \"id\": syntax error"
+    1, "Unrecognized syntax near 'id'"
     -- </default-5.2>
 })
 
@@ -234,7 +234,7 @@ test:do_catchsql_test(
         CREATE TABLE t6(id INTEGER PRIMARY KEY, b TEXT DEFAULT "id");
     ]], {
     -- <default-5.3>
-    1, "near \"\"id\"\": syntax error"
+    1, "Unrecognized syntax near '\"id\"'"
     -- </default-5.3>
 })
 
diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua
index 75fe81e..9ade46c 100755
--- a/test/sql-tap/e_select1.test.lua
+++ b/test/sql-tap/e_select1.test.lua
@@ -105,7 +105,7 @@ test:do_catchsql_test(
         SELECT count(*) FROM t1, t2 USING (a) ON (t1.a=t2.a)
     ]], {
         -- <e_select-0.1.5>
-        1, [[keyword "ON" is reserved]]
+        1, [[Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.]]
         -- </e_select-0.1.5>
     })
 
@@ -807,14 +807,14 @@ test:do_select_tests(
 -- FROM clause.
 --
 data = {
-    {"1.1", "SELECT a, b, c FROM z1 WHERE *",  'near \"*\": syntax error'},
-    {"1.2", "SELECT a, b, c FROM z1 GROUP BY *", 'near \"*\": syntax error'},
-    {"1.3", "SELECT 1 + * FROM z1",  'near \"*\": syntax error'},
-    {"1.4", "SELECT * + 1 FROM z1", 'near \"+\": syntax error'},
-    {"2.1", "SELECT *", 'no tables specified'},
-    {"2.2", "SELECT * WHERE 1", 'no tables specified'},
-    {"2.3", "SELECT * WHERE 0", 'no tables specified'},
-    {"2.4", "SELECT count(*), *", 'no tables specified' }
+    {"1.1", "SELECT a, b, c FROM z1 WHERE *",  "Unrecognized syntax near '*'"},
+    {"1.2", "SELECT a, b, c FROM z1 GROUP BY *", "Unrecognized syntax near '*'"},
+    {"1.3", "SELECT 1 + * FROM z1",  "Unrecognized syntax near '*'"},
+    {"1.4", "SELECT * + 1 FROM z1", "Unrecognized syntax near '+'"},
+    {"2.1", "SELECT *", "Failed to expand '*' in SELECT statement without FROM clause"},
+    {"2.2", "SELECT * WHERE 1", "Failed to expand '*' in SELECT statement without FROM clause"},
+    {"2.3", "SELECT * WHERE 0", "Failed to expand '*' in SELECT statement without FROM clause"},
+    {"2.4", "SELECT count(*), *", "Failed to expand '*' in SELECT statement without FROM clause"}
 }
 
 for _, val in ipairs(data) do
diff --git a/test/sql-tap/gh-2367-pragma.test.lua b/test/sql-tap/gh-2367-pragma.test.lua
index d874bce..f54fdb6 100755
--- a/test/sql-tap/gh-2367-pragma.test.lua
+++ b/test/sql-tap/gh-2367-pragma.test.lua
@@ -51,7 +51,7 @@ test:do_catchsql_test(
 	[[
 		pragma sql_default_engine 'memtx';
 	]], {
-	1, 'near \"\'memtx\'\": syntax error'
+	1, "Unrecognized syntax near ''memtx''"
 })
 
 test:do_catchsql_test(
@@ -59,7 +59,7 @@ test:do_catchsql_test(
 	[[
 		pragma sql_default_engine 1;
 	]], {
-	1, 'near \"1\": syntax error'
+	1, "Unrecognized syntax near '1'"
 })
 
 test:finish_test()
diff --git a/test/sql-tap/gh2168-temp-tables.test.lua b/test/sql-tap/gh2168-temp-tables.test.lua
index 536e187..0de4be5 100755
--- a/test/sql-tap/gh2168-temp-tables.test.lua
+++ b/test/sql-tap/gh2168-temp-tables.test.lua
@@ -8,7 +8,7 @@ test:do_catchsql_test(
 		CREATE TEMP TABLE tmp1 (id INTEGER PRIMARY KEY);
 	]], {
 		-- <trigger2-10.1>
-	1, "near \"TEMP\": syntax error"	
+	1, "Unrecognized syntax near 'TEMP'"
 		-- <trigger2-10.1>
 });
 
@@ -23,7 +23,7 @@ test:do_catchsql_test(
 		END;
 	]], {
 		-- <trigger2-10.1>
-	1, "near \"TEMP\": syntax error"	
+	1, "Unrecognized syntax near 'TEMP'"
 		-- <trigger2-10.1>
 });
 
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 923d5e6..e2b408a 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -238,7 +238,7 @@ test:do_catchsql_test(
 data = {
     { 1,  [[ 'a' < 'b' collate binary ]], {1, "Collation 'BINARY' does not exist"}},
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {1}}},
-    { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[near "'binary'": syntax error]]}},
+    { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Unrecognized syntax near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {1}}},
     { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {1}}},
     { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
diff --git a/test/sql-tap/index-info.test.lua b/test/sql-tap/index-info.test.lua
index d052e8c..499f620 100755
--- a/test/sql-tap/index-info.test.lua
+++ b/test/sql-tap/index-info.test.lua
@@ -26,7 +26,7 @@ test:do_catchsql_test(
     "index-info-1.2",
     "PRAGMA index_info = t1.a;",
     {
-        1, "near \".\": syntax error",
+        1, "Unrecognized syntax near '.'",
     })
 
 -- Case: single column index with an integer column.
diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua
index 2ed1451..5dbeb84 100755
--- a/test/sql-tap/index1.test.lua
+++ b/test/sql-tap/index1.test.lua
@@ -994,7 +994,7 @@ test:do_catchsql_test(
         CREATE INDEX temp.i21 ON t6(c);
     ]], {
         -- <index-21.1>
-        1, "near \".\": syntax error"
+        1, "Unrecognized syntax near '.'"
         -- </index-21.1>
     })
 
diff --git a/test/sql-tap/index7.test.lua b/test/sql-tap/index7.test.lua
index 0a7fe60..7dd9efa 100755
--- a/test/sql-tap/index7.test.lua
+++ b/test/sql-tap/index7.test.lua
@@ -292,7 +292,7 @@ test:do_catchsql_test(
         CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER);
         CREATE UNIQUE INDEX i ON t1 (a) WHERE a = 3;
     ]], {
-        1, "keyword \"WHERE\" is reserved"
+        1, "Keyword 'WHERE' is reserved. Please use double quotes if 'WHERE' is an identifier."
     })
 
 -- Currently, when a user tries to create index (or primary key,
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index bda4091..df272a9 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -570,7 +570,7 @@ test:do_catchsql_test(
         SELECT * FROM t1 USING(a) 
     ]], {
         -- <join-3.5>
-        1, "a JOIN clause is required before USING"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </join-3.5>
     })
 
diff --git a/test/sql-tap/keyword1.test.lua b/test/sql-tap/keyword1.test.lua
index 6895dc1..33873d1 100755
--- a/test/sql-tap/keyword1.test.lua
+++ b/test/sql-tap/keyword1.test.lua
@@ -237,7 +237,7 @@ for _, kw in ipairs(bannedkws) do
     test:do_catchsql_test(
         "bannedkw1-"..kw..".1",
         query, {
-            1, 'keyword "'..kw..'" is reserved'
+            1, "Keyword '"..kw.."' is reserved. Please use double quotes if '"..kw.."' is an identifier."
         })
 end
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index 4358b58..6d2d813 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -271,7 +271,7 @@ test:do_catchsql_test(
         UPDATE t3 SET a=0 WHEREwww b=2;
     ]], {
         -- <misc1-5.1>
-        1, [[near "WHEREwww": syntax error]]
+        1, [[Unrecognized syntax near 'WHEREwww']]
         -- </misc1-5.1>
     })
 
@@ -413,7 +413,7 @@ test:do_catchsql_test(
         SELECT *;
     ]], {
         -- <misc1-8.1>
-        1, "no tables specified"
+        1, "Failed to expand '*' in SELECT statement without FROM clause"
         -- </misc1-8.1>
     })
 
@@ -1037,7 +1037,7 @@ test:do_catchsql_test(
         select''like''like''like#0;
     ]], {
         -- <misc1-21.1>
-        1, [[near "#0": syntax error]]
+        1, [[Unrecognized syntax near '#0']]
         -- </misc1-21.1>
     })
 
@@ -1047,7 +1047,7 @@ test:do_catchsql_test(
         VALUES(0,0x0MATCH#0;
     ]], {
         -- <misc1-21.2>
-        1, [[near ";": syntax error]]
+        1, [[Unrecognized syntax near ';']]
         -- </misc1-21.2>
     })
 
diff --git a/test/sql-tap/misc5.test.lua b/test/sql-tap/misc5.test.lua
index 0852741..5f98f21 100755
--- a/test/sql-tap/misc5.test.lua
+++ b/test/sql-tap/misc5.test.lua
@@ -299,7 +299,7 @@ test:do_test(
         return test:catchsql(sql)
     end, {
         -- <misc5-7.1>
-        1, "parser stack overflow"
+        1, "Failed to parse SQL statement: parser stack limit reached"
         -- </misc5-7.1>
     })
 
@@ -347,7 +347,7 @@ test:do_catchsql_test(
         SELECT 123abc
     ]], {
         -- <misc5-10.1>
-        1, [[unrecognized token: "123abc"]]
+        1, [[Syntax error: unrecognized token: '123abc']]
         -- </misc5-10.1>
     })
 
@@ -357,7 +357,7 @@ test:do_catchsql_test(
         SELECT 1*123.4e5ghi;
     ]], {
         -- <misc5-10.2>
-        1, [[unrecognized token: "123.4e5ghi"]]
+        1, [[Syntax error: unrecognized token: '123.4e5ghi']]
         -- </misc5-10.2>
     })
 
diff --git a/test/sql-tap/null.test.lua b/test/sql-tap/null.test.lua
index 66135d3..456ec03 100755
--- a/test/sql-tap/null.test.lua
+++ b/test/sql-tap/null.test.lua
@@ -517,7 +517,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "near \"1\": syntax error"
+    1, "Unrecognized syntax near '1'"
     -- <index-1.3>
     })
 
@@ -528,7 +528,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "near \"1\": syntax error"
+    1, "Unrecognized syntax near '1'"
     -- <index-1.3>
     })
 
@@ -539,7 +539,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "near \"1\": syntax error"
+    1, "Unrecognized syntax near '1'"
     -- <index-1.3>
     })
 
@@ -550,7 +550,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "near \"1\": syntax error"
+    1, "Unrecognized syntax near '1'"
     -- <index-1.3>
     })
 
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index 6c35b6f..57f3fcb 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -1406,7 +1406,7 @@ test:do_catchsql_test(
         SELECT f1 FROM test1 WHERE f2=;
     ]], {
         -- <select1-7.1>
-        1, [[near ";": syntax error]]
+        1, [[Unrecognized syntax near ';']]
         -- </select1-7.1>
     })
 
@@ -1416,7 +1416,7 @@ test:do_catchsql_test(
             SELECT f1 FROM test1 UNION SELECT WHERE;
         ]], {
             -- <select1-7.2>
-            1, [[keyword "WHERE" is reserved]]
+            1, [[Keyword 'WHERE' is reserved. Please use double quotes if 'WHERE' is an identifier.]]
             -- </select1-7.2>
         })
 
@@ -1428,7 +1428,7 @@ test:do_catchsql_test(
     [[
         SELECT f1 FROM test1 as "hi", test2 as]], {
         -- <select1-7.3>
-        1, [[keyword "as" is reserved]]
+        1, [[Keyword 'as' is reserved. Please use double quotes if 'as' is an identifier.]]
         -- </select1-7.3>
     })
 
@@ -1438,7 +1438,7 @@ test:do_catchsql_test(
         SELECT f1 FROM test1 ORDER BY;
     ]], {
         -- <select1-7.4>
-        1, [[near ";": syntax error]]
+        1, [[Unrecognized syntax near ';']]
         -- </select1-7.4>
     })
 
@@ -1448,7 +1448,7 @@ test:do_catchsql_test(
         SELECT f1 FROM test1 ORDER BY f1 desc, f2 where;
     ]], {
         -- <select1-7.5>
-        1, [[keyword "where" is reserved]]
+        1, [[Keyword 'where' is reserved. Please use double quotes if 'where' is an identifier.]]
         -- </select1-7.5>
     })
 
@@ -1458,7 +1458,7 @@ test:do_catchsql_test(
         SELECT count(f1,f2 FROM test1;
     ]], {
         -- <select1-7.6>
-        1, [[keyword "FROM" is reserved]]
+        1, [[Keyword 'FROM' is reserved. Please use double quotes if 'FROM' is an identifier.]]
         -- </select1-7.6>
     })
 
@@ -1468,7 +1468,7 @@ test:do_catchsql_test(
         SELECT count(f1,f2+) FROM test1;
     ]], {
         -- <select1-7.7>
-        1, [[near ")": syntax error]]
+        1, [[Unrecognized syntax near ')']]
         -- </select1-7.7>
     })
 
@@ -1478,7 +1478,7 @@ test:do_catchsql_test(
         SELECT f1 FROM test1 ORDER BY f2, f1+;
     ]], {
         -- <select1-7.8>
-        1, [[near ";": syntax error]]
+        1, [[Unrecognized syntax near ';']]
         -- </select1-7.8>
     })
 
@@ -1488,7 +1488,7 @@ test:do_catchsql_test(
         SELECT f1 FROM test1 LIMIT 5+3 OFFSET 11 ORDER BY f2;
     ]], {
         -- <select1-7.9>
-        1, [[keyword "ORDER" is reserved]]
+        1, [[Keyword 'ORDER' is reserved. Please use double quotes if 'ORDER' is an identifier.]]
         -- </select1-7.9>
     })
 
@@ -2075,7 +2075,7 @@ test:do_catchsql_test(
         SELECT 1 FROM (SELECT *)
     ]], {
         -- <select1-16.1>
-        1, "no tables specified"
+        1, "Failed to expand '*' in SELECT statement without FROM clause"
         -- </select1-16.1>
     })
 
diff --git a/test/sql-tap/select3.test.lua b/test/sql-tap/select3.test.lua
index e7e306e..6ae3135 100755
--- a/test/sql-tap/select3.test.lua
+++ b/test/sql-tap/select3.test.lua
@@ -182,7 +182,7 @@ test:do_catchsql_test("select3-2.13", [[
   SELECT log, count(*) FROM t1 GROUP BY ORDER BY log;
 ]], {
   -- <select3-2.13>
-  1, [[keyword "ORDER" is reserved]]
+  1, [[Keyword 'ORDER' is reserved. Please use double quotes if 'ORDER' is an identifier.]]
   -- </select3-2.13>
 })
 
@@ -190,7 +190,7 @@ test:do_catchsql_test("select3-2.14", [[
   SELECT log, count(*) FROM t1 GROUP BY;
 ]], {
   -- <select3-2.14>
-  1, [[near ";": syntax error]]
+  1, [[Unrecognized syntax near ';']]
   -- </select3-2.14>
 })
 
diff --git a/test/sql-tap/start-transaction.test.lua b/test/sql-tap/start-transaction.test.lua
index 82356ae..feb55a2 100755
--- a/test/sql-tap/start-transaction.test.lua
+++ b/test/sql-tap/start-transaction.test.lua
@@ -21,7 +21,7 @@ test:do_catchsql_test(
 		COMMIT;
 	]], {
 		-- <start-transaction-1.0>
-		1, "near \"BEGIN\": syntax error"
+		1, "Unrecognized syntax near 'BEGIN'"
 		-- <start-transaction-1.0>
 	})
 
@@ -46,7 +46,7 @@ test:do_catchsql_test(
 		COMMIT;
 	]], {
 		-- <start-transaction-1.1>
-		1, "near \"BEGIN\": syntax error"
+		1, "Unrecognized syntax near 'BEGIN'"
 		-- <start-transaction-1.1>
 	})
 
@@ -94,7 +94,7 @@ test:do_catchsql_test(
 		COMMIT TRANSACTION;
 	]], {
 		-- <start-transaction-1.6>
-		1, "keyword \"TRANSACTION\" is reserved"
+		1, "Keyword 'TRANSACTION' is reserved. Please use double quotes if 'TRANSACTION' is an identifier."
 		-- <start-transaction-1.6>
 	})
 
@@ -119,7 +119,7 @@ test:do_catchsql_test(
 		END;
 	]], {
 		-- <start-transaction-1.8>
-		1, "keyword \"END\" is reserved"
+		1, "Keyword 'END' is reserved. Please use double quotes if 'END' is an identifier."
 		-- <start-transaction-1.8>
 	})
 
@@ -144,7 +144,7 @@ test:do_catchsql_test(
 		END TRANSACTION;
 	]], {
 		-- <start-transaction-1.10>
-		1, "keyword \"END\" is reserved"
+		1, "Keyword 'END' is reserved. Please use double quotes if 'END' is an identifier."
 		-- <start-transaction-1.10>
 	})
 
@@ -193,7 +193,7 @@ test:do_catchsql_test(
 		COMMIT;
 	]], {
 		-- <start-transaction-1.14>
-		1, "keyword \"TRANSACTION\" is reserved"
+		1, "Keyword 'TRANSACTION' is reserved. Please use double quotes if 'TRANSACTION' is an identifier."
 		-- <start-transaction-1.14>
 	})
 
@@ -246,7 +246,7 @@ test:do_catchsql_test(
 		COMMIT;
 	]], {
 		-- <start-transaction-1.18>
-		1, "keyword \"TRANSACTION\" is reserved"
+		1, "Keyword 'TRANSACTION' is reserved. Please use double quotes if 'TRANSACTION' is an identifier."
 		-- <start-transaction-1.18>
 	})
 
diff --git a/test/sql-tap/table.test.lua b/test/sql-tap/table.test.lua
index 2bcc5aa..c487e1e 100755
--- a/test/sql-tap/table.test.lua
+++ b/test/sql-tap/table.test.lua
@@ -620,7 +620,7 @@ test:do_catchsql_test(
 		CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b VARCHAR(10));
 	]], {
 	-- <temp>
-	1, "near \"TEMP\": syntax error"
+	1, "Unrecognized syntax near 'TEMP'"
 	-- <temp>
 	})
 
@@ -630,7 +630,7 @@ test:do_catchsql_test(
 		CREATE TEMPORARY TABLE t1(a INTEGER PRIMARY KEY, b VARCHAR(10));
 	]], {
 	-- <temporary>
-	1, "near \"TEMPORARY\": syntax error"
+	1, "Unrecognized syntax near 'TEMPORARY'"
 	-- <temporary>
 	})
 
@@ -1253,7 +1253,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <table-22.1>
-        1,"keyword \"CONSTRAINT\" is reserved"
+        1,"Keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
         -- </table-22.1>
     })
 
@@ -1318,7 +1318,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <table-22.6>
-        1,"keyword \"CONSTRAINT\" is reserved"
+        1,"Keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
         -- </table-22.6>
     })
 
@@ -1332,7 +1332,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <table-22.7>
-        1,"keyword \"CONSTRAINT\" is reserved"
+        1,"Keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
         -- </table-22.7>
     })
 
diff --git a/test/sql-tap/tkt3935.test.lua b/test/sql-tap/tkt3935.test.lua
index e13391c..cc8fea7 100755
--- a/test/sql-tap/tkt3935.test.lua
+++ b/test/sql-tap/tkt3935.test.lua
@@ -57,7 +57,7 @@ test:do_catchsql_test(
         SELECT a FROM (t1) AS t ON b USING(a) 
     ]], {
         -- <tkt3935.4>
-        1, "a JOIN clause is required before ON"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.4>
     })
 
@@ -67,7 +67,7 @@ test:do_catchsql_test(
         SELECT a FROM (t1) AS t ON b 
     ]], {
         -- <tkt3935.5>
-        1, "a JOIN clause is required before ON"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.5>
     })
 
@@ -77,7 +77,7 @@ test:do_catchsql_test(
         SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) 
     ]], {
         -- <tkt3935.6>
-        1, "a JOIN clause is required before ON"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.6>
     })
 
@@ -87,7 +87,7 @@ test:do_catchsql_test(
         SELECT a FROM (SELECT * FROM t1) AS t ON b 
     ]], {
         -- <tkt3935.7>
-        1, "a JOIN clause is required before ON"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.7>
     })
 
@@ -97,7 +97,7 @@ test:do_catchsql_test(
         SELECT a FROM t1 AS t ON b 
     ]], {
         -- <tkt3935.8>
-        1, "a JOIN clause is required before ON"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.8>
     })
 
@@ -107,7 +107,7 @@ test:do_catchsql_test(
         SELECT a FROM t1 AS t ON b USING(a) 
     ]], {
         -- <tkt3935.9>
-        1, "a JOIN clause is required before ON"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.9>
     })
 
@@ -117,7 +117,7 @@ test:do_catchsql_test(
         SELECT a FROM t1 AS t USING(a) 
     ]], {
         -- <tkt3935.10>
-        1, "a JOIN clause is required before USING"
+        1, "Syntax error in FROM clause: a JOIN clause is required before ON and USING"
         -- </tkt3935.10>
     })
 
diff --git a/test/sql-tap/tokenize.test.lua b/test/sql-tap/tokenize.test.lua
index 9ef4fd0..0c79f75 100755
--- a/test/sql-tap/tokenize.test.lua
+++ b/test/sql-tap/tokenize.test.lua
@@ -26,7 +26,7 @@ test:do_catchsql_test(
         SELECT 1.0e+
     ]], {
         -- <tokenize-1.1>
-        1, [[unrecognized token: "1.0e"]]
+        1, [[Syntax error: unrecognized token: '1.0e']]
         -- </tokenize-1.1>
     })
 
@@ -36,7 +36,7 @@ test:do_catchsql_test(
         SELECT 1.0E+
     ]], {
         -- <tokenize-1.2>
-        1, [[unrecognized token: "1.0E"]]
+        1, [[Syntax error: unrecognized token: '1.0E']]
         -- </tokenize-1.2>
     })
 
@@ -46,7 +46,7 @@ test:do_catchsql_test(
         SELECT 1.0e-
     ]], {
         -- <tokenize-1.3>
-        1, [[unrecognized token: "1.0e"]]
+        1, [[Syntax error: unrecognized token: '1.0e']]
         -- </tokenize-1.3>
     })
 
@@ -56,7 +56,7 @@ test:do_catchsql_test(
         SELECT 1.0E-
     ]], {
         -- <tokenize-1.4>
-        1, [[unrecognized token: "1.0E"]]
+        1, [[Syntax error: unrecognized token: '1.0E']]
         -- </tokenize-1.4>
     })
 
@@ -66,7 +66,7 @@ test:do_catchsql_test(
         SELECT 1.0e+/
     ]], {
         -- <tokenize-1.5>
-        1, [[unrecognized token: "1.0e"]]
+        1, [[Syntax error: unrecognized token: '1.0e']]
         -- </tokenize-1.5>
     })
 
@@ -76,7 +76,7 @@ test:do_catchsql_test(
         SELECT 1.0E+:
     ]], {
         -- <tokenize-1.6>
-        1, [[unrecognized token: "1.0E"]]
+        1, [[Syntax error: unrecognized token: '1.0E']]
         -- </tokenize-1.6>
     })
 
@@ -86,7 +86,7 @@ test:do_catchsql_test(
         SELECT 1.0e-:
     ]], {
         -- <tokenize-1.7>
-        1, [[unrecognized token: "1.0e"]]
+        1, [[Syntax error: unrecognized token: '1.0e']]
         -- </tokenize-1.7>
     })
 
@@ -96,7 +96,7 @@ test:do_catchsql_test(
         SELECT 1.0E-/
     ]], {
         -- <tokenize-1.8>
-        1, [[unrecognized token: "1.0E"]]
+        1, [[Syntax error: unrecognized token: '1.0E']]
         -- </tokenize-1.8>
     })
 
@@ -106,7 +106,7 @@ test:do_catchsql_test(
         SELECT 1.0F+5
     ]], {
         -- <tokenize-1.9>
-        1, [[unrecognized token: "1.0F"]]
+        1, [[Syntax error: unrecognized token: '1.0F']]
         -- </tokenize-1.9>
     })
 
@@ -116,7 +116,7 @@ test:do_catchsql_test(
         SELECT 1.0d-10
     ]], {
         -- <tokenize-1.10>
-        1, [[unrecognized token: "1.0d"]]
+        1, [[Syntax error: unrecognized token: '1.0d']]
         -- </tokenize-1.10>
     })
 
@@ -126,7 +126,7 @@ test:do_catchsql_test(
         SELECT 1.0e,5
     ]], {
         -- <tokenize-1.11>
-        1, [[unrecognized token: "1.0e"]]
+        1, [[Syntax error: unrecognized token: '1.0e']]
         -- </tokenize-1.11>
     })
 
@@ -136,7 +136,7 @@ test:do_catchsql_test(
         SELECT 1.0E.10
     ]], {
         -- <tokenize-1.12>
-        1, [[unrecognized token: "1.0E"]]
+        1, [[Syntax error: unrecognized token: '1.0E']]
         -- </tokenize-1.12>
     })
 
@@ -145,7 +145,7 @@ test:do_catchsql_test(
     [[
         SELECT 1, 2 /*]], {
         -- <tokenize-2.1>
-        1, [[near "*": syntax error]]
+        1, [[Unrecognized syntax near '*']]
         -- </tokenize-2.1>
     })
 
diff --git a/test/sql-tap/trigger1.test.lua b/test/sql-tap/trigger1.test.lua
index 871a144..d0edcd7 100755
--- a/test/sql-tap/trigger1.test.lua
+++ b/test/sql-tap/trigger1.test.lua
@@ -72,7 +72,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-1.1.3>
-        1, [[near "STATEMENT": syntax error]]
+        1, [[Unrecognized syntax near 'STATEMENT']]
         -- </trigger1-1.1.3>
     })
 
@@ -297,7 +297,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-2.1>
-        1, [[near ";": syntax error]]
+        1, [[Unrecognized syntax near ';']]
         -- </trigger1-2.1>
     })
 
@@ -310,7 +310,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-2.2>
-        1, [[near ";": syntax error]]
+        1, [[Unrecognized syntax near ';']]
         -- </trigger1-2.2>
     })
 
@@ -809,7 +809,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.4>
-        1, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error in trigger body: the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.4>
     })
 
@@ -821,7 +821,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.5>
-        1, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error in trigger body: the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.5>
     })
 
@@ -833,7 +833,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.6>
-        1, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error in trigger body: the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.6>
     })
 
@@ -845,7 +845,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.7>
-        1, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error in trigger body: the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.7>
     })
 
diff --git a/test/sql-tap/view.test.lua b/test/sql-tap/view.test.lua
index c99a0a5..2808ac7 100755
--- a/test/sql-tap/view.test.lua
+++ b/test/sql-tap/view.test.lua
@@ -293,7 +293,7 @@ test:do_catchsql_test(
         CREATE VIEW v1err(x,y DESC,z) AS SELECT a, b+c, c-b FROM t1;
     ]], {
         -- <view-3.3.4>
-        1, [[keyword "DESC" is reserved]]
+        1, [[Keyword 'DESC' is reserved. Please use double quotes if 'DESC' is an identifier.]]
         -- </view-3.3.4>
     })
 
@@ -961,7 +961,7 @@ test:do_catchsql_test(
         DROP VIEW main.nosuchview
     ]], {
         -- <view-17.2>
-        1, "near \".\": syntax error"
+        1, "Unrecognized syntax near '.'"
         -- </view-17.2>
     })
 
diff --git a/test/sql-tap/with1.test.lua b/test/sql-tap/with1.test.lua
index 7896483..add2345 100755
--- a/test/sql-tap/with1.test.lua
+++ b/test/sql-tap/with1.test.lua
@@ -178,7 +178,7 @@ test:do_catchsql_test(3.6, [[
   SELECT * FROM tmp;
 ]], {
   -- <3.6>
-  1, [[keyword "SELECT" is reserved]]
+  1, [[Keyword 'SELECT' is reserved. Please use double quotes if 'SELECT' is an identifier.]]
   -- </3.6>
 })
 
@@ -1018,7 +1018,7 @@ test:do_catchsql_test(13.1, [[
   SELECT i FROM c;
 ]], {
   -- <13.1>
-  1, "no tables specified"
+  1, "Failed to expand '*' in SELECT statement without FROM clause"
   -- </13.1>
 })
 
@@ -1027,7 +1027,7 @@ test:do_catchsql_test(13.2, [[
   SELECT i FROM c;
 ]], {
   -- <13.2>
-  1, "no tables specified"
+  1, "Failed to expand '*' in SELECT statement without FROM clause"
   -- </13.2>
 })
 
diff --git a/test/sql-tap/with2.test.lua b/test/sql-tap/with2.test.lua
index c27a9d1..9700729 100755
--- a/test/sql-tap/with2.test.lua
+++ b/test/sql-tap/with2.test.lua
@@ -317,7 +317,7 @@ test:do_catchsql_test(4.1, [[
     SELECT * FROM x;
 ]], {
     -- <4.1>
-    1, [[near ")": syntax error]]
+    1, [[Unrecognized syntax near ')']]
     -- </4.1>
 })
 
@@ -519,7 +519,7 @@ test:do_catchsql_test(6.2, [[
     INSERT INTO t2 VALUES(1, 2,);
 ]], {
     -- <6.2>
-    1, [[near ")": syntax error]]
+    1, [[Unrecognized syntax near ')']]
     -- </6.2>
 })
 
@@ -528,7 +528,7 @@ test:do_catchsql_test("6.3.1", [[
     INSERT INTO t2 SELECT a, b, FROM t1;
 ]], {
     -- <6.3>
-    1, [[keyword "FROM" is reserved]]
+    1, [[Keyword 'FROM' is reserved. Please use double quotes if 'FROM' is an identifier.]]
     -- </6.3>
 })
 
@@ -546,7 +546,7 @@ test:do_catchsql_test(6.4, [[
     INSERT INTO t2 SELECT a, b, FROM t1 a a a;
 ]], {
     -- <6.4>
-    1, [[keyword "FROM" is reserved]]
+    1, [[Keyword 'FROM' is reserved. Please use double quotes if 'FROM' is an identifier.]]
     -- </6.4>
 })
 
@@ -555,7 +555,7 @@ test:do_catchsql_test(6.5, [[
     DELETE FROM t2 WHERE;
 ]], {
     -- <6.5>
-    1, [[near ";": syntax error]]
+    1, [[Unrecognized syntax near ';']]
     -- </6.5>
 })
 
@@ -563,7 +563,7 @@ test:do_catchsql_test(6.6, [[
     WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHERE
 ]], {
     -- <6.6>
-    1, '/near .* syntax error/'
+    1, "Unrecognized syntax near '\n'"
     -- </6.6>
 })
 
@@ -571,7 +571,7 @@ test:do_catchsql_test(6.7, [[
     WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHRE 1;
 ]], {
     -- <6.7>
-    1, '/near .* syntax error/'
+    1, "Unrecognized syntax near 'WHRE'"
     -- </6.7>
 })
 
@@ -579,7 +579,7 @@ test:do_catchsql_test(6.8, [[
     WITH x AS (SELECT * FROM t1) UPDATE t2 SET a = 10, b = ;
 ]], {
     -- <6.8>
-    1, '/near .* syntax error/'
+    1, "Unrecognized syntax near ';'"
     -- </6.8>
 })
 
@@ -587,7 +587,7 @@ test:do_catchsql_test(6.9, [[
     WITH x AS (SELECT * FROM t1) UPDATE t2 SET a = 10, b = 1 WHERE a===b;
 ]], {
     -- <6.9>
-    1, '/near .* syntax error/'
+    1, "Unrecognized syntax near '='"
     -- </6.9>
 })
 
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 2eafae8..cfce2e4 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -30,7 +30,7 @@ t = {513, 1, 'test', 'memtx', 0, opts, format}
 s = box.space._space:insert(t)
 ---
 - error: 'Wrong space options (field 5): invalid expression specified (SQL error:
-    near "<": syntax error)'
+    Unrecognized syntax near ''<'')'
 ...
 opts = {checks = {{expr = 'X>5'}}}
 ---
diff --git a/test/sql/collation.result b/test/sql/collation.result
index daea355..bad265d 100644
--- a/test/sql/collation.result
+++ b/test/sql/collation.result
@@ -14,23 +14,23 @@ box.sql.execute('pragma sql_default_engine=\''..engine..'\'')
 -- All of these tests should throw error "near "COLLATE": syntax error"
 box.sql.execute("SELECT 1 LIMIT 1 COLLATE BINARY;")
 ---
-- error: 'near "COLLATE": syntax error'
+- error: Unrecognized syntax near 'COLLATE'
 ...
 box.sql.execute("SELECT 1 LIMIT 1 COLLATE BINARY OFFSET 1;")
 ---
-- error: 'near "COLLATE": syntax error'
+- error: Unrecognized syntax near 'COLLATE'
 ...
 box.sql.execute("SELECT 1 LIMIT 1 OFFSET 1 COLLATE BINARY;")
 ---
-- error: 'near "COLLATE": syntax error'
+- error: Unrecognized syntax near 'COLLATE'
 ...
 box.sql.execute("SELECT 1 LIMIT 1, 1 COLLATE BINARY;")
 ---
-- error: 'near "COLLATE": syntax error'
+- error: Unrecognized syntax near 'COLLATE'
 ...
 box.sql.execute("SELECT 1 LIMIT 1 COLLATE BINARY, 1;")
 ---
-- error: 'near "COLLATE": syntax error'
+- error: Unrecognized syntax near 'COLLATE'
 ...
 -- gh-3052: upper/lower support only default locale
 -- For tr-TR result depends on collation
@@ -102,7 +102,7 @@ cn = remote.connect(box.cfg.listen)
 ...
 cn:execute('select 1 limit ? collate not_exist', {1})
 ---
-- error: 'Failed to execute SQL statement: near "COLLATE": syntax error'
+- error: 'Failed to execute SQL statement: Unrecognized syntax near ''COLLATE'''
 ...
 cn:close()
 ---
diff --git a/test/sql/foreign-keys.result b/test/sql/foreign-keys.result
index becb4c2..3c6464e 100644
--- a/test/sql/foreign-keys.result
+++ b/test/sql/foreign-keys.result
@@ -358,19 +358,21 @@ box.sql.execute('CREATE TABLE t1 (id INT PRIMARY KEY);')
 ...
 box.sql.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE RESTRICT);')
 ---
-- error: keyword "DELETE" is reserved
+- error: Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an
+    identifier.
 ...
 box.sql.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE CASCADE);')
 ---
-- error: keyword "DELETE" is reserved
+- error: Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an
+    identifier.
 ...
 box.sql.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON UPDATE RESTRICT ON DELETE RESTRICT);')
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE MATCH FULL);')
 ---
-- error: keyword "MATCH" is reserved
+- error: Keyword 'MATCH' is reserved. Please use double quotes if 'MATCH' is an identifier.
 ...
 box.space.T1:drop()
 ---
diff --git a/test/sql/gh-3888-values-blob-assert.result b/test/sql/gh-3888-values-blob-assert.result
index 67948cd..600acf7 100644
--- a/test/sql/gh-3888-values-blob-assert.result
+++ b/test/sql/gh-3888-values-blob-assert.result
@@ -16,20 +16,20 @@ box.sql.execute('pragma sql_default_engine=\''..engine..'\'')
 -- check 'VALUES' against typedef keywords (should fail)
 box.sql.execute('VALUES(blob)')
 ---
-- error: 'near "blob": syntax error'
+- error: Unrecognized syntax near 'blob'
 ...
 box.sql.execute('VALUES(float)')
 ---
-- error: 'near "float": syntax error'
+- error: Unrecognized syntax near 'float'
 ...
 -- check 'SELECT' against typedef keywords (should fail)
 box.sql.execute('SELECT blob')
 ---
-- error: 'near "blob": syntax error'
+- error: Unrecognized syntax near 'blob'
 ...
 box.sql.execute('SELECT float')
 ---
-- error: 'near "float": syntax error'
+- error: Unrecognized syntax near 'float'
 ...
 -- check 'VALUES' against ID (should fail)
 box.sql.execute('VALUES(TheColumnName)')
diff --git a/test/sql/iproto.result b/test/sql/iproto.result
index 562e068..aa59635 100644
--- a/test/sql/iproto.result
+++ b/test/sql/iproto.result
@@ -96,7 +96,7 @@ cn:execute('insert into not_existing_table values ("kek")')
 ...
 cn:execute('insert qwerty gjsdjq  q  qwd qmq;; q;qwd;')
 ---
-- error: 'Failed to execute SQL statement: near "qwerty": syntax error'
+- error: 'Failed to execute SQL statement: Unrecognized syntax near ''qwerty'''
 ...
 -- Empty result.
 cn:execute('select id as identifier from test where a = 5;')
@@ -109,7 +109,7 @@ cn:execute('select id as identifier from test where a = 5;')
 -- netbox API errors.
 cn:execute(100)
 ---
-- error: 'Failed to execute SQL statement: near "100": syntax error'
+- error: 'Failed to execute SQL statement: Unrecognized syntax near ''100'''
 ...
 cn:execute('select 1', nil, {dry_run = true})
 ---
@@ -118,11 +118,11 @@ cn:execute('select 1', nil, {dry_run = true})
 -- Empty request.
 cn:execute('')
 ---
-- error: 'Failed to execute SQL statement: syntax error: empty request'
+- error: 'Failed to execute SQL statement: Failed to execute an empty SQL statement'
 ...
 cn:execute('   ;')
 ---
-- error: 'Failed to execute SQL statement: syntax error: empty request'
+- error: 'Failed to execute SQL statement: Failed to execute an empty SQL statement'
 ...
 --
 -- gh-3467: allow only positive integers under limit clause.
@@ -567,7 +567,7 @@ cn:execute('drop table if exists test3')
 --
 cn:execute('select ?1, ?2, ?3', {1, 2, 3})
 ---
-- error: 'Failed to execute SQL statement: near "?1": syntax error'
+- error: 'Failed to execute SQL statement: Unrecognized syntax near ''?1'''
 ...
 cn:execute('select $name, $name2', {1, 2})
 ---
diff --git a/test/sql/misc.result b/test/sql/misc.result
index ef104c1..9a8aa8d 100644
--- a/test/sql/misc.result
+++ b/test/sql/misc.result
@@ -14,11 +14,13 @@ box.sql.execute('select 1;')
 ...
 box.sql.execute('select 1; select 2;')
 ---
-- error: keyword "select" is reserved
+- error: Keyword 'select' is reserved. Please use double quotes if 'select' is an
+    identifier.
 ...
 box.sql.execute('create table t1 (id INT primary key); select 100;')
 ---
-- error: keyword "select" is reserved
+- error: Keyword 'select' is reserved. Please use double quotes if 'select' is an
+    identifier.
 ...
 box.space.t1 == nil
 ---
@@ -26,17 +28,17 @@ box.space.t1 == nil
 ...
 box.sql.execute(';')
 ---
-- error: 'syntax error: empty request'
+- error: Failed to execute an empty SQL statement
 ...
 box.sql.execute('')
 ---
-- error: 'syntax error: empty request'
+- error: Failed to execute an empty SQL statement
 ...
 box.sql.execute('     ;')
 ---
-- error: 'syntax error: empty request'
+- error: Failed to execute an empty SQL statement
 ...
 box.sql.execute('\n\n\n\t\t\t   ')
 ---
-- error: 'syntax error: empty request'
+- error: Failed to execute an empty SQL statement
 ...
diff --git a/test/sql/on-conflict.result b/test/sql/on-conflict.result
index 07bb403..6d37e69 100644
--- a/test/sql/on-conflict.result
+++ b/test/sql/on-conflict.result
@@ -13,37 +13,37 @@ box.sql.execute('pragma sql_default_engine=\''..engine..'\'')
 --
 box.sql.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT ABORT)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute("CREATE TABLE q (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT FAIL)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute("CREATE TABLE p (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT IGNORE)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute("CREATE TABLE g (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT REPLACE)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute("CREATE TABLE e (id INTEGER PRIMARY KEY ON CONFLICT REPLACE, v INTEGER)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute("CREATE TABLE t1(a INT PRIMARY KEY ON CONFLICT REPLACE)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 box.sql.execute("CREATE TABLE t2(a INT PRIMARY KEY ON CONFLICT IGNORE)")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 -- CHECK constraint is illegal with REPLACE option.
 --
 box.sql.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER CHECK (a > 5) ON CONFLICT REPLACE);")
 ---
-- error: keyword "ON" is reserved
+- error: Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
 ...
 --
 -- gh-3473: Primary key can't be declared with NULL.
diff --git a/test/sql/types.result b/test/sql/types.result
index a0159d6..82f2873 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -8,23 +8,26 @@ test_run = env.new()
 --
 box.sql.execute("CREATE TABLE t1 (id PRIMARY KEY);")
 ---
-- error: keyword "PRIMARY" is reserved
+- error: Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an
+    identifier.
 ...
 box.sql.execute("CREATE TABLE t1 (a, id INT PRIMARY KEY);")
 ---
-- error: 'near ",": syntax error'
+- error: Unrecognized syntax near ','
 ...
 box.sql.execute("CREATE TABLE t1 (id PRIMARY KEY, a INT);")
 ---
-- error: keyword "PRIMARY" is reserved
+- error: Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an
+    identifier.
 ...
 box.sql.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a);")
 ---
-- error: 'near ")": syntax error'
+- error: Unrecognized syntax near ')'
 ...
 box.sql.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b UNIQUE);")
 ---
-- error: keyword "UNIQUE" is reserved
+- error: Keyword 'UNIQUE' is reserved. Please use double quotes if 'UNIQUE' is an
+    identifier.
 ...
 -- gh-3104: real type is stored in space format.
 --
-- 
2.7.4

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

* [tarantool-patches] [PATCH v2 3/5] sql: save SQL parser errors in diag_set()
  2019-02-25 17:14 [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL imeevma
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error imeevma
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 2/5] sql: rework syntax errors imeevma
@ 2019-02-25 17:14 ` imeevma
  2019-02-25 23:01   ` [tarantool-patches] " n.pettik
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse imeevma
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 5/5] sql: remove field nErr " imeevma
  4 siblings, 1 reply; 21+ messages in thread
From: imeevma @ 2019-02-25 17:14 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

After this patch all SQL parser errors will be saved in diag_set()
instead of field zErrMsg of struct Parse.

Part of #3965
---
 src/box/errcode.h           | 1 +
 src/box/sql/build.c         | 3 ++-
 src/box/sql/util.c          | 6 +++---
 test/box/misc.result        | 1 +
 test/sql-tap/check.test.lua | 2 +-
 test/sql/triggers.result    | 4 ++--
 6 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/src/box/errcode.h b/src/box/errcode.h
index 6546b2f..779d927 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -238,6 +238,7 @@ struct errcode_record {
 	/*183 */_(ER_SQL_KEYWORD_IS_RESERVED,	"Keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
 	/*184 */_(ER_SQL_SYNTAX_NEAR,		"Unrecognized syntax near '%.*s'") \
 	/*185 */_(ER_SQL_UNKNOWN_TOKEN,		"Syntax error: unrecognized token: '%.*s'") \
+	/*186 */_(ER_SQL_PARSER_GENERIC,	"%s") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index f112c9f..deb5b89 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -194,7 +194,8 @@ sql_finish_coding(struct Parse *parse_context)
 		sqlVdbeMakeReady(v, parse_context);
 		parse_context->rc = SQL_DONE;
 	} else {
-		parse_context->rc = SQL_ERROR;
+		if (parse_context->rc != SQL_TARANTOOL_ERROR)
+			parse_context->rc = SQL_ERROR;
 	}
 }
 /**
diff --git a/src/box/sql/util.c b/src/box/sql/util.c
index c89e2e8..e4c93cb 100644
--- a/src/box/sql/util.c
+++ b/src/box/sql/util.c
@@ -236,10 +236,10 @@ sqlErrorMsg(Parse * pParse, const char *zFormat, ...)
 	va_start(ap, zFormat);
 	zMsg = sqlVMPrintf(db, zFormat, ap);
 	va_end(ap);
+	diag_set(ClientError, ER_SQL_PARSER_GENERIC, zMsg);
+	sqlDbFree(db, zMsg);
 	pParse->nErr++;
-	sqlDbFree(db, pParse->zErrMsg);
-	pParse->zErrMsg = zMsg;
-	pParse->rc = SQL_ERROR;
+	pParse->rc = SQL_TARANTOOL_ERROR;
 }
 
 void
diff --git a/test/box/misc.result b/test/box/misc.result
index a1c94bf..47393d1 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -514,6 +514,7 @@ t;
   182: box.error.SQL_STATEMENT_EMPTY
   184: box.error.SQL_SYNTAX_NEAR
   185: box.error.SQL_UNKNOWN_TOKEN
+  186: box.error.SQL_PARSER_GENERIC
 ...
 test_run:cmd("setopt delimiter ''");
 ---
diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua
index f7d3ffe..8ce3184 100755
--- a/test/sql-tap/check.test.lua
+++ b/test/sql-tap/check.test.lua
@@ -319,7 +319,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-3.1>
-        1, "Failed to create space 'T3': SQL error: subqueries prohibited in CHECK constraints"
+        1, "Failed to create space 'T3': subqueries prohibited in CHECK constraints"
         -- </check-3.1>
     })
 
diff --git a/test/sql/triggers.result b/test/sql/triggers.result
index bbfff33..9ab169b 100644
--- a/test/sql/triggers.result
+++ b/test/sql/triggers.result
@@ -398,14 +398,14 @@ space_id = box.space.T1.id
 ...
 box.sql.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.a = ? BEGIN SELECT 1; END;")
 ---
-- error: 'SQL error: bindings are not allowed in DDL'
+- error: bindings are not allowed in DDL
 ...
 tuple = {"TR1", space_id, {sql = [[CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.a = ? BEGIN SELECT 1; END;]]}}
 ---
 ...
 box.space._trigger:insert(tuple)
 ---
-- error: 'SQL error: bindings are not allowed in DDL'
+- error: bindings are not allowed in DDL
 ...
 box.sql.execute("DROP TABLE t1;")
 ---
-- 
2.7.4

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

* [tarantool-patches] [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse
  2019-02-25 17:14 [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL imeevma
                   ` (2 preceding siblings ...)
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 3/5] sql: save SQL parser errors in diag_set() imeevma
@ 2019-02-25 17:14 ` imeevma
  2019-02-26 14:47   ` [tarantool-patches] " n.pettik
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 5/5] sql: remove field nErr " imeevma
  4 siblings, 1 reply; 21+ messages in thread
From: imeevma @ 2019-02-25 17:14 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

This field become unused and should be removed.

Part of #3965
---
 src/box/sql.c                 | 11 +++--------
 src/box/sql/build.c           | 14 ++++----------
 src/box/sql/delete.c          | 23 +++++++----------------
 src/box/sql/prepare.c         | 12 +++---------
 src/box/sql/resolve.c         |  9 +++------
 src/box/sql/sqlInt.h          |  3 +--
 src/box/sql/tokenize.c        | 37 +++++++------------------------------
 src/box/sql/trigger.c         |  6 ------
 test/sql-tap/check.test.lua   |  4 ++--
 test/sql-tap/select3.test.lua |  2 +-
 test/sql-tap/select5.test.lua | 10 +++++-----
 test/sql/checks.result        | 12 ++++++------
 test/sql/delete.result        |  5 ++---
 test/sql/on-conflict.result   |  3 +--
 14 files changed, 45 insertions(+), 106 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index 580f3fa..116e3e8 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1362,13 +1362,8 @@ sql_checks_resolve_space_def_reference(ExprList *expr_list,
 	parser.parse_only = true;
 
 	sql_resolve_self_reference(&parser, def, NC_IsCheck, NULL, expr_list);
-	int rc = 0;
-	if (parser.rc != SQL_OK) {
-		/* Tarantool error may be already set with diag. */
-		if (parser.rc != SQL_TARANTOOL_ERROR)
-			diag_set(ClientError, ER_SQL, parser.zErrMsg);
-		rc = -1;
-	}
+	if (parser.rc != SQL_OK)
+		return -1;
 	sql_parser_destroy(&parser);
-	return rc;
+	return 0;
 }
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index deb5b89..6afca4a 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -493,16 +493,10 @@ sql_column_add_nullable_action(struct Parse *parser,
 	struct field_def *field = &def->fields[def->field_count - 1];
 	if (field->nullable_action != ON_CONFLICT_ACTION_DEFAULT &&
 	    nullable_action != field->nullable_action) {
-		/* Prevent defining nullable_action many times. */
-		const char *err_msg =
-			tt_sprintf("NULL declaration for column '%s' of table "
-				   "'%s' has been already set to '%s'",
-				   field->name, def->name,
-				   on_conflict_action_strs[field->
-							   nullable_action]);
-		diag_set(ClientError, ER_SQL, err_msg);
-		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
+		sqlErrorMsg(parser, "NULL declaration for column '%s' of "\
+			    "table '%s' has been already set to '%s'",
+			    field->name, def->name,
+			    on_conflict_action_strs[field-> nullable_action]);
 		return;
 	}
 	field->nullable_action = nullable_action;
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 5170c7f..a7bf3b3 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -94,31 +94,22 @@ sql_table_truncate(struct Parse *parse, struct SrcList *tab_list)
 	struct space *space = space_by_name(tab_name);
 	if (space == NULL) {
 		diag_set(ClientError, ER_NO_SUCH_SPACE, tab_name);
-		goto tarantool_error;
+		sql_parser_error(parse);
 	}
 	if (! rlist_empty(&space->parent_fk_constraint)) {
-		const char *err_msg =
-			tt_sprintf("can not truncate space '%s' because other "
-				   "objects depend on it", space->def->name);
-		diag_set(ClientError, ER_SQL, err_msg);
-		goto tarantool_error;
+		sqlErrorMsg(parse, "can not truncate space '%s' because other "
+			    "objects depend on it", space->def->name);
+		goto cleanup;
 	}
 	if (space->def->opts.is_view) {
-		const char *err_msg =
-			tt_sprintf("can not truncate space '%s' because it is "
-				   "a view", space->def->name);
-		diag_set(ClientError, ER_SQL, err_msg);
-		goto tarantool_error;
+		sqlErrorMsg(parse, "can not truncate space '%s' because it is "
+			    "a view", space->def->name);
+		goto cleanup;
 	}
 	sqlVdbeAddOp2(v, OP_Clear, space->def->id, true);
 cleanup:
 	sqlSrcListDelete(parse->db, tab_list);
 	return;
-
-tarantool_error:
-	parse->rc = SQL_TARANTOOL_ERROR;
-	parse->nErr++;
-	goto cleanup;
 }
 
 void
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index d4ba55b..feeefb1 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -52,7 +52,6 @@ sqlPrepare(sql * db,	/* Database handle. */
 	       const char **pzTail	/* OUT: End of parsed string */
     )
 {
-	char *zErrMsg = 0;	/* Error message */
 	int rc = SQL_OK;	/* Result code */
 	int i;			/* Loop counter */
 	Parse sParse;		/* Parsing context */
@@ -90,14 +89,14 @@ sqlPrepare(sql * db,	/* Database handle. */
 		}
 		zSqlCopy = sqlDbStrNDup(db, zSql, nBytes);
 		if (zSqlCopy) {
-			sqlRunParser(&sParse, zSqlCopy, &zErrMsg);
+			sqlRunParser(&sParse, zSqlCopy);
 			sParse.zTail = &zSql[sParse.zTail - zSqlCopy];
 			sqlDbFree(db, zSqlCopy);
 		} else {
 			sParse.zTail = &zSql[nBytes];
 		}
 	} else {
-		sqlRunParser(&sParse, zSql, &zErrMsg);
+		sqlRunParser(&sParse, zSql);
 	}
 	assert(0 == sParse.nQueryLoop);
 
@@ -146,11 +145,7 @@ sqlPrepare(sql * db,	/* Database handle. */
 		*ppStmt = (sql_stmt *) sParse.pVdbe;
 	}
 
-	if (zErrMsg) {
-		sqlErrorWithMsg(db, rc, "%s", zErrMsg);
-	} else {
-		sqlError(db, rc);
-	}
+	sqlError(db, rc);
 
 	/* Delete any TriggerPrg structures allocated while parsing this statement. */
 	while (sParse.pTriggerPrg) {
@@ -295,7 +290,6 @@ sql_parser_destroy(Parse *parser)
 		db->lookaside.bDisable -= parser->disableLookaside;
 	}
 	parser->disableLookaside = 0;
-	sqlDbFree(db, parser->zErrMsg);
 	switch (parser->parsed_ast_type) {
 	case AST_TYPE_SELECT:
 		sql_select_delete(db, parser->parsed_ast.select);
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index aed9e26..1339157 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -1332,12 +1332,9 @@ resolveSelectStep(Walker * pWalker, Select * p)
 				return WRC_Abort;
 			if ((sNC.ncFlags & NC_HasAgg) == 0 ||
 			    (sNC.ncFlags & NC_HasUnaggregatedId) != 0) {
-				diag_set(ClientError, ER_SQL, "HAVING "
-					 "argument must appear in the GROUP BY "
-					 "clause or be used in an aggregate "
-					 "function");
-				pParse->nErr++;
-				pParse->rc = SQL_TARANTOOL_ERROR;
+				sqlErrorMsg(pParse, "HAVING argument must "\
+					    "appear in the GROUP BY clause or "\
+					    "be used in an aggregate function");
 				return WRC_Abort;
 			}
 			/*
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index dbfdbc6..1a28f1a 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2653,7 +2653,6 @@ struct fk_constraint_parse {
  */
 struct Parse {
 	sql *db;		/* The main database structure */
-	char *zErrMsg;		/* An error message */
 	Vdbe *pVdbe;		/* An engine for executing database bytecode */
 	int rc;			/* Return code from execution */
 	u8 colNamesSet;		/* TRUE after OP_ColumnName has been issued to pVdbe */
@@ -3221,7 +3220,7 @@ void sqlDequote(char *);
 void sqlNormalizeName(char *z);
 void sqlTokenInit(Token *, char *);
 int sqlKeywordCode(const unsigned char *, int);
-int sqlRunParser(Parse *, const char *, char **);
+int sqlRunParser(Parse *, const char *);
 
 /**
  * Increment error counter.
diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
index 44a7bb9..5ea0ea5 100644
--- a/src/box/sql/tokenize.c
+++ b/src/box/sql/tokenize.c
@@ -445,7 +445,7 @@ parser_space_delete(struct sql *db, struct space *space)
  * error message.
  */
 int
-sqlRunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
+sqlRunParser(Parse * pParse, const char *zSql)
 {
 	int nErr = 0;		/* Number of errors encountered */
 	int i;			/* Loop counter */
@@ -463,7 +463,6 @@ sqlRunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
 	pParse->rc = SQL_OK;
 	pParse->zTail = zSql;
 	i = 0;
-	assert(pzErrMsg != 0);
 	/* sqlParserTrace(stdout, "parser: "); */
 	pEngine = sqlParserAlloc(sqlMalloc);
 	if (pEngine == 0) {
@@ -531,22 +530,8 @@ sqlRunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
 	if (db->mallocFailed) {
 		pParse->rc = SQL_NOMEM_BKPT;
 	}
-	if (pParse->rc != SQL_OK && pParse->rc != SQL_DONE
-	    && pParse->zErrMsg == 0) {
-		const char *error;
-		if (is_tarantool_error(pParse->rc) &&
-		    tarantoolErrorMessage() != NULL)
-			error = tarantoolErrorMessage();
-		else
-			error = sqlErrStr(pParse->rc);
-		pParse->zErrMsg = sqlMPrintf(db, "%s", error);
-	}
-	assert(pzErrMsg != 0);
-	if (pParse->zErrMsg) {
-		*pzErrMsg = pParse->zErrMsg;
-		sql_log(pParse->rc, "%s", *pzErrMsg);
+	if (pParse->rc != SQL_OK && pParse->rc != SQL_DONE)
 		nErr++;
-	}
 	if (pParse->pVdbe != NULL && pParse->nErr > 0) {
 		sqlVdbeDelete(pParse->pVdbe);
 		pParse->pVdbe = 0;
@@ -577,11 +562,8 @@ sql_expr_compile(sql *db, const char *expr, int expr_len)
 	}
 	sprintf(stmt, "%s%.*s", outer, expr_len, expr);
 
-	char *sql_error = NULL;
-	if (sqlRunParser(&parser, stmt, &sql_error) != SQL_OK ||
-	    parser.parsed_ast_type != AST_TYPE_EXPR) {
-		diag_set(ClientError, ER_SQL, sql_error);
-	} else {
+	if (sqlRunParser(&parser, stmt) == SQL_OK &&
+	    parser.parsed_ast_type == AST_TYPE_EXPR) {
 		expression = parser.parsed_ast.expr;
 		parser.parsed_ast.expr = NULL;
 	}
@@ -599,8 +581,7 @@ sql_view_compile(struct sql *db, const char *view_stmt)
 
 	struct Select *select = NULL;
 
-	char *unused;
-	if (sqlRunParser(&parser, view_stmt, &unused) != SQL_OK ||
+	if (sqlRunParser(&parser, view_stmt) != SQL_OK ||
 	    parser.parsed_ast_type != AST_TYPE_SELECT) {
 		diag_set(ClientError, ER_SQL_EXECUTE, view_stmt);
 	} else {
@@ -618,13 +599,9 @@ sql_trigger_compile(struct sql *db, const char *sql)
 	struct Parse parser;
 	sql_parser_create(&parser, db);
 	parser.parse_only = true;
-	char *sql_error = NULL;
 	struct sql_trigger *trigger = NULL;
-	if (sqlRunParser(&parser, sql, &sql_error) != SQL_OK ||
-	    parser.parsed_ast_type != AST_TYPE_TRIGGER) {
-	    if (parser.rc != SQL_TARANTOOL_ERROR)
-		diag_set(ClientError, ER_SQL, sql_error);
-	} else {
+	if (sqlRunParser(&parser, sql) == SQL_OK &&
+	    parser.parsed_ast_type == AST_TYPE_TRIGGER) {
 		trigger = parser.parsed_ast.trigger;
 		parser.parsed_ast.trigger = NULL;
 	}
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index f7e6189..4c7ab8a 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -730,16 +730,10 @@ onErrorText(int onError)
 static void
 transferParseError(Parse * pTo, Parse * pFrom)
 {
-	assert(pFrom->zErrMsg == 0 || pFrom->nErr);
-	assert(pTo->zErrMsg == 0 || pTo->nErr);
 	if (pTo->nErr == 0) {
-		pTo->zErrMsg = pFrom->zErrMsg;
 		pTo->nErr = pFrom->nErr;
 		pTo->rc = pFrom->rc;
-	} else {
-		sqlDbFree(pFrom->db, pFrom->zErrMsg);
 	}
-	pFrom->zErrMsg = NULL;
 }
 
 /**
diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua
index 8ce3184..c2e9a91 100755
--- a/test/sql-tap/check.test.lua
+++ b/test/sql-tap/check.test.lua
@@ -516,7 +516,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-5.1>
-        1, "Wrong space options (field 5): invalid expression specified (SQL error: bindings are not allowed in DDL)"
+        1, "Wrong space options (field 5): invalid expression specified (bindings are not allowed in DDL)"
         -- </check-5.1>
     })
 
@@ -528,7 +528,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-5.2>
-        1, "Wrong space options (field 5): invalid expression specified (SQL error: bindings are not allowed in DDL)"
+        1, "Wrong space options (field 5): invalid expression specified (bindings are not allowed in DDL)"
         -- </check-5.2>
     })
 
diff --git a/test/sql-tap/select3.test.lua b/test/sql-tap/select3.test.lua
index 6ae3135..c68ca4d 100755
--- a/test/sql-tap/select3.test.lua
+++ b/test/sql-tap/select3.test.lua
@@ -200,7 +200,7 @@ test:do_catchsql_test("select3-3.1", [[
   SELECT log, count(*) FROM t1 HAVING log>=4
 ]], {
   -- <select3-3.1>
-  1, "SQL error: HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
+  1, "HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
   -- </select3-3.1>
 })
 
diff --git a/test/sql-tap/select5.test.lua b/test/sql-tap/select5.test.lua
index d47e340..180576b 100755
--- a/test/sql-tap/select5.test.lua
+++ b/test/sql-tap/select5.test.lua
@@ -424,7 +424,7 @@ test:do_catchsql_test(
         SELECT s1 FROM te40 HAVING s1 = 1;
     ]], {
     -- <select5-9.1>
-    1, "SQL error: HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
+    1, "HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
     -- </select5-9.1>
 })
 
@@ -434,7 +434,7 @@ test:do_catchsql_test(
         SELECT SUM(s1) FROM te40 HAVING s1 = 2;
     ]], {
     -- <select5-9.2>
-    1, "SQL error: HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
+    1, "HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
     -- </select5-9.2>
 })
 
@@ -444,7 +444,7 @@ test:do_catchsql_test(
         SELECT s1 FROM te40 HAVING SUM(s1) = 2;
     ]], {
     -- <select5-9.3>
-    1, "SQL error: HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
+    1, "HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
     -- </select5-9.3>
 })
 
@@ -484,7 +484,7 @@ test:do_catchsql_test(
         SELECT SUM(s1),s2 FROM te40 HAVING SUM(s1) > 0;
     ]], {
     -- <select5-9.7>
-    1, "SQL error: HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
+    1, "HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
     -- </select5-9.7>
 })
 
@@ -494,7 +494,7 @@ test:do_catchsql_test(
         SELECT SUM(s1) FROM te40 HAVING SUM(s1) > 0 and s2 > 0;
     ]], {
     -- <select5-9.8>
-    1, "SQL error: HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
+    1, "HAVING argument must appear in the GROUP BY clause or be used in an aggregate function"
     -- </select5-9.8>
 })
 
diff --git a/test/sql/checks.result b/test/sql/checks.result
index cfce2e4..e6a6b72 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -29,8 +29,8 @@ t = {513, 1, 'test', 'memtx', 0, opts, format}
 ...
 s = box.space._space:insert(t)
 ---
-- error: 'Wrong space options (field 5): invalid expression specified (SQL error:
-    Unrecognized syntax near ''<'')'
+- error: 'Wrong space options (field 5): invalid expression specified (Unrecognized
+    syntax near ''<'')'
 ...
 opts = {checks = {{expr = 'X>5'}}}
 ---
@@ -122,8 +122,8 @@ box.sql.execute("DROP TABLE w2;")
 --
 box.sql.execute("CREATE TABLE t5(x INT PRIMARY KEY, y INT, CHECK( x*y < ? ));")
 ---
-- error: 'Wrong space options (field 5): invalid expression specified (SQL error:
-    bindings are not allowed in DDL)'
+- error: 'Wrong space options (field 5): invalid expression specified (bindings are
+    not allowed in DDL)'
 ...
 opts = {checks = {{expr = '?>5', name = 'ONE'}}}
 ---
@@ -136,8 +136,8 @@ t = {513, 1, 'test', 'memtx', 0, opts, format}
 ...
 s = box.space._space:insert(t)
 ---
-- error: 'Wrong space options (field 5): invalid expression specified (SQL error:
-    bindings are not allowed in DDL)'
+- error: 'Wrong space options (field 5): invalid expression specified (bindings are
+    not allowed in DDL)'
 ...
 test_run:cmd("clear filter")
 ---
diff --git a/test/sql/delete.result b/test/sql/delete.result
index e024dd6..a0c8352 100644
--- a/test/sql/delete.result
+++ b/test/sql/delete.result
@@ -93,7 +93,7 @@ box.sql.execute("CREATE VIEW v1 AS SELECT * FROM t1;")
 ...
 box.sql.execute("TRUNCATE TABLE v1;")
 ---
-- error: 'SQL error: can not truncate space ''V1'' because it is a view'
+- error: can not truncate space 'V1' because it is a view
 ...
 -- Can't truncate table with FK.
 box.sql.execute("CREATE TABLE t2(x INT PRIMARY KEY REFERENCES t1(id));")
@@ -101,8 +101,7 @@ box.sql.execute("CREATE TABLE t2(x INT PRIMARY KEY REFERENCES t1(id));")
 ...
 box.sql.execute("TRUNCATE TABLE t1;")
 ---
-- error: 'SQL error: can not truncate space ''T1'' because other objects depend on
-    it'
+- error: can not truncate space 'T1' because other objects depend on it
 ...
 -- Table triggers should be ignored.
 box.sql.execute("DROP TABLE t2;")
diff --git a/test/sql/on-conflict.result b/test/sql/on-conflict.result
index 6d37e69..6ddce86 100644
--- a/test/sql/on-conflict.result
+++ b/test/sql/on-conflict.result
@@ -58,8 +58,7 @@ box.sql.execute("CREATE TABLE te17 (s1 INT NULL PRIMARY KEY);")
 ...
 box.sql.execute("CREATE TABLE test (a int PRIMARY KEY, b int NULL ON CONFLICT IGNORE);")
 ---
-- error: 'SQL error: NULL declaration for column ''B'' of table ''TEST'' has been
-    already set to ''none'''
+- error: NULL declaration for column 'B' of table 'TEST' has been already set to 'none'
 ...
 box.sql.execute("CREATE TABLE test (a int, b int NULL, c int, PRIMARY KEY(a, b, c))")
 ---
-- 
2.7.4

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

* [tarantool-patches] [PATCH v2 5/5] sql: remove field nErr of struct Parse
  2019-02-25 17:14 [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL imeevma
                   ` (3 preceding siblings ...)
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse imeevma
@ 2019-02-25 17:14 ` imeevma
  2019-02-26  8:27   ` [tarantool-patches] " Konstantin Osipov
  2019-02-26 14:48   ` n.pettik
  4 siblings, 2 replies; 21+ messages in thread
From: imeevma @ 2019-02-25 17:14 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

At the moment, the only purpose of the field nErr of struct Parse
is to show whether the field rc of the same struct is
SQL_TARANTOOL_ERROR RC or not. Let's remove it.

Part of #3965
---
 src/box/sql.c           |  2 --
 src/box/sql/alter.c     |  1 -
 src/box/sql/analyze.c   |  2 --
 src/box/sql/build.c     | 62 ++++++++++++++++++-------------------------------
 src/box/sql/callback.c  |  1 -
 src/box/sql/delete.c    |  7 +++---
 src/box/sql/expr.c      | 26 +++++++++++----------
 src/box/sql/insert.c    |  4 ++--
 src/box/sql/parse.y     | 16 ++++++-------
 src/box/sql/pragma.c    |  5 +---
 src/box/sql/resolve.c   | 13 ++++++-----
 src/box/sql/select.c    | 30 ++++++++++++------------
 src/box/sql/sqlInt.h    |  9 -------
 src/box/sql/tokenize.c  |  4 ++--
 src/box/sql/trigger.c   | 21 +++--------------
 src/box/sql/update.c    |  4 ++--
 src/box/sql/util.c      |  8 -------
 src/box/sql/where.c     |  3 +--
 src/box/sql/wherecode.c |  5 ++--
 19 files changed, 83 insertions(+), 140 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index 116e3e8..6402673 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1276,7 +1276,6 @@ sql_ephemeral_space_def_new(struct Parse *parser, const char *name)
 		diag_set(OutOfMemory, size, "region_alloc",
 			 "sql_ephemeral_space_def_new");
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return NULL;
 	}
 
@@ -1295,7 +1294,6 @@ sql_ephemeral_space_new(Parse *parser, const char *name)
 	if (space == NULL) {
 		diag_set(OutOfMemory, sz, "region", "space");
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return NULL;
 	}
 
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index d49ebb8..214e0f8 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -73,7 +73,6 @@ exit_rename_table:
 tnt_error:
 	sqlDbFree(db, new_name);
 	parse->rc = SQL_TARANTOOL_ERROR;
-	parse->nErr++;
 	goto exit_rename_table;
 }
 
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 8c83288..96e5e4c 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -908,7 +908,6 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 			diag_set(OutOfMemory, sizeof(int) * part_count,
 				 "region", "jump_addrs");
 			parse->rc = SQL_TARANTOOL_ERROR;
-			parse->nErr++;
 			return;
 		}
 		/*
@@ -1131,7 +1130,6 @@ sqlAnalyze(Parse * pParse, Token * pName)
 			} else {
 				diag_set(ClientError, ER_NO_SUCH_SPACE, z);
 				pParse->rc = SQL_TARANTOOL_ERROR;
-				pParse->nErr++;
 			}
 			sqlDbFree(db, z);
 		}
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 6afca4a..6621af4 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -92,7 +92,6 @@ save_record(struct Parse *parser, uint32_t space_id, int reg_key,
 		diag_set(OutOfMemory, sizeof(*record), "region_alloc",
 			 "record");
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return;
 	}
 	record->space_id = space_id;
@@ -145,9 +144,11 @@ sql_finish_coding(struct Parse *parse_context)
 			     "Exit with an error if CREATE statement fails"));
 	}
 
-	if (db->mallocFailed || parse_context->nErr != 0) {
-		if (parse_context->rc == SQL_OK)
-			parse_context->rc = SQL_ERROR;
+	if (parse_context->rc == SQL_TARANTOOL_ERROR)
+		return;
+	if (db->mallocFailed) {
+		diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Out of memory");
+		parse_context->rc = SQL_TARANTOOL_ERROR;
 		return;
 	}
 	/*
@@ -189,13 +190,13 @@ sql_finish_coding(struct Parse *parse_context)
 		sqlVdbeGoto(v, 1);
 	}
 	/* Get the VDBE program ready for execution. */
-	if (parse_context->nErr == 0 && !db->mallocFailed) {
+	if (parse_context->rc != SQL_TARANTOOL_ERROR && !db->mallocFailed) {
 		assert(parse_context->iCacheLevel == 0);
 		sqlVdbeMakeReady(v, parse_context);
 		parse_context->rc = SQL_DONE;
-	} else {
-		if (parse_context->rc != SQL_TARANTOOL_ERROR)
-			parse_context->rc = SQL_ERROR;
+	} else if (parse_context->rc != SQL_TARANTOOL_ERROR) {
+		diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Out of memory");
+		parse_context->rc = SQL_TARANTOOL_ERROR;
 	}
 }
 /**
@@ -345,7 +346,7 @@ sqlStartTable(Parse *pParse, Token *pName, int noErr)
 	if (space != NULL) {
 		if (!noErr) {
 			diag_set(ClientError, ER_SPACE_EXISTS, zName);
-			sql_parser_error(pParse);
+			pParse->rc = SQL_TARANTOOL_ERROR;
 		} else {
 			assert(!db->init.busy || CORRUPT_DB);
 		}
@@ -398,7 +399,6 @@ sql_field_retrieve(Parse *parser, struct space_def *space_def, uint32_t id)
 				sizeof(space_def->fields[0]),
 				"region_alloc", "sql_field_retrieve");
 			parser->rc = SQL_TARANTOOL_ERROR;
-			parser->nErr++;
 			return NULL;
 		}
 
@@ -454,7 +454,6 @@ sqlAddColumn(Parse * pParse, Token * pName, struct type_def *type_def)
 		diag_set(OutOfMemory, pName->n + 1,
 			 "region_alloc", "z");
 		pParse->rc = SQL_TARANTOOL_ERROR;
-		pParse->nErr++;
 		return;
 	}
 	memcpy(z, pName->z, pName->n);
@@ -463,7 +462,7 @@ sqlAddColumn(Parse * pParse, Token * pName, struct type_def *type_def)
 	for (uint32_t i = 0; i < def->field_count; i++) {
 		if (strcmp(z, def->fields[i].name) == 0) {
 			diag_set(ClientError, ER_SPACE_FIELD_IS_DUPLICATE, z);
-			sql_parser_error(pParse);
+			pParse->rc = SQL_TARANTOOL_ERROR;
 			return;
 		}
 	}
@@ -538,7 +537,6 @@ sqlAddDefaultValue(Parse * pParse, ExprSpan * pSpan)
 					 "region_alloc",
 					 "field->default_value");
 				pParse->rc = SQL_TARANTOOL_ERROR;
-				pParse->nErr++;
 				return;
 			}
 			strncpy(field->default_value, pSpan->zStart,
@@ -557,7 +555,6 @@ field_def_create_for_pk(struct Parse *parser, struct field_def *field,
 	    field->nullable_action != ON_CONFLICT_ACTION_DEFAULT) {
 		diag_set(ClientError, ER_NULLABLE_PRIMARY, space_name);
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return -1;
 	} else if (field->nullable_action == ON_CONFLICT_ACTION_DEFAULT) {
 		field->nullable_action = ON_CONFLICT_ACTION_ABORT;
@@ -646,7 +643,7 @@ sqlAddPrimaryKey(Parse * pParse,	/* Parsing context */
 		sql_create_index(pParse, 0, 0, pList, 0, sortOrder, false,
 				 SQL_INDEX_TYPE_CONSTRAINT_PK);
 		pList = 0;
-		if (pParse->nErr > 0)
+		if (pParse->rc == SQL_TARANTOOL_ERROR)
 			goto primary_key_exit;
 	}
 
@@ -846,8 +843,6 @@ vdbe_emit_create_index(struct Parse *parse, struct space_def *def,
 	return;
 error:
 	parse->rc = SQL_TARANTOOL_ERROR;
-	parse->nErr++;
-
 }
 
 /*
@@ -905,7 +900,6 @@ createSpace(Parse * pParse, int iSpaceId, char *zStmt)
 	save_record(pParse, BOX_SPACE_ID, iFirstCol, 1, v->nOp - 1);
 	return;
 error:
-	pParse->nErr++;
 	pParse->rc = SQL_TARANTOOL_ERROR;
 }
 
@@ -1086,7 +1080,6 @@ vdbe_emit_fk_constraint_create(struct Parse *parse_context,
 	sqlReleaseTempRange(parse_context, constr_tuple_reg, 10);
 	return;
 error:
-	parse_context->nErr++;
 	parse_context->rc = SQL_TARANTOOL_ERROR;
 }
 
@@ -1116,7 +1109,6 @@ resolve_link(struct Parse *parse_context, const struct space_def *def,
 		 tt_sprintf("unknown column %s in foreign key definition",
 			    field_name));
 	parse_context->rc = SQL_TARANTOOL_ERROR;
-	parse_context->nErr++;
 	return -1;
 }
 
@@ -1248,7 +1240,6 @@ sqlEndTable(Parse * pParse,	/* Parse context */
 					 "number of columns in the primary "\
 					 "index of referenced table");
 				pParse->rc = SQL_TARANTOOL_ERROR;
-				pParse->nErr++;
 				return;
 			}
 			for (uint32_t i = 0; i < fk_def->field_count; ++i) {
@@ -1278,7 +1269,7 @@ sql_create_view(struct Parse *parse_context, struct Token *begin,
 	}
 	sqlStartTable(parse_context, name, if_exists);
 	struct space *space = parse_context->new_space;
-	if (space == NULL || parse_context->nErr != 0)
+	if (space == NULL || parse_context->rc == SQL_TARANTOOL_ERROR)
 		goto create_view_fail;
 
 	struct space *select_res_space =
@@ -1324,7 +1315,6 @@ sql_create_view(struct Parse *parse_context, struct Token *begin,
 	if (space->def->opts.sql == NULL) {
 		diag_set(OutOfMemory, n, "strndup", "opts.sql");
 		parse_context->rc = SQL_TARANTOOL_ERROR;
-		parse_context->nErr++;
 		goto create_view_fail;
 	}
 
@@ -1597,14 +1587,14 @@ sql_drop_table(struct Parse *parse_context, struct SrcList *table_name_list,
 		goto exit_drop_table;
 	}
 	sqlVdbeCountChanges(v);
-	assert(parse_context->nErr == 0);
+	assert(parse_context->rc != SQL_TARANTOOL_ERROR);
 	assert(table_name_list->nSrc == 1);
 	const char *space_name = table_name_list->a[0].zName;
 	struct space *space = space_by_name(space_name);
 	if (space == NULL) {
 		if (!if_exists) {
 			diag_set(ClientError, ER_NO_SUCH_SPACE, space_name);
-			sql_parser_error(parse_context);
+			parse_context->rc = SQL_TARANTOOL_ERROR;
 		}
 		goto exit_drop_table;
 	}
@@ -1644,7 +1634,6 @@ sql_drop_table(struct Parse *parse_context, struct SrcList *table_name_list,
 			diag_set(ClientError, ER_DROP_SPACE, space_name,
 				 "other objects depend on it");
 			parse_context->rc = SQL_TARANTOOL_ERROR;
-			parse_context->nErr++;
 			goto exit_drop_table;
 		}
 	}
@@ -1680,7 +1669,6 @@ columnno_by_name(struct Parse *parse_context, const struct space *space,
 			 tt_sprintf("foreign key refers to nonexistent field %s",
 				    column_name));
 		parse_context->rc = SQL_TARANTOOL_ERROR;
-		parse_context->nErr++;
 		return -1;
 	}
 	return 0;
@@ -1890,7 +1878,6 @@ exit_create_fk:
 	return;
 tnt_error:
 	parse_context->rc = SQL_TARANTOOL_ERROR;
-	parse_context->nErr++;
 	goto exit_create_fk;
 }
 
@@ -1915,7 +1902,6 @@ sql_drop_foreign_key(struct Parse *parse_context, struct SrcList *table,
 	if (child == NULL) {
 		diag_set(ClientError, ER_NO_SUCH_SPACE, table_name);
 		parse_context->rc = SQL_TARANTOOL_ERROR;
-		parse_context->nErr++;
 		return;
 	}
 	char *constraint_name = sqlNameFromToken(parse_context->db,
@@ -2042,7 +2028,7 @@ index_fill_def(struct Parse *parse, struct index *index,
 		struct Expr *expr = expr_list->a[i].pExpr;
 		sql_resolve_self_reference(parse, space_def, NC_IdxExpr,
 					   expr, 0);
-		if (parse->nErr > 0)
+		if (parse->rc == SQL_TARANTOOL_ERROR)
 			goto cleanup;
 
 		struct Expr *column_expr = sqlExprSkipCollate(expr);
@@ -2094,7 +2080,6 @@ cleanup:
 	return rc;
 tnt_error:
 	parse->rc = SQL_TARANTOOL_ERROR;
-	++parse->nErr;
 	goto cleanup;
 }
 
@@ -2122,7 +2107,7 @@ sql_create_index(struct Parse *parse, struct Token *token,
 	struct sql *db = parse->db;
 	assert(!db->init.busy);
 
-	if (db->mallocFailed || parse->nErr > 0)
+	if (db->mallocFailed || parse->rc == SQL_TARANTOOL_ERROR)
 		goto exit_create_index;
 	if (idx_type == SQL_INDEX_TYPE_UNIQUE ||
 	    idx_type == SQL_INDEX_TYPE_NON_UNIQUE) {
@@ -2145,7 +2130,6 @@ sql_create_index(struct Parse *parse, struct Token *token,
 			if (! if_not_exist) {
 				diag_set(ClientError, ER_NO_SUCH_SPACE, name);
 				parse->rc = SQL_TARANTOOL_ERROR;
-				parse->nErr++;
 			}
 			goto exit_create_index;
 		}
@@ -2191,7 +2175,7 @@ sql_create_index(struct Parse *parse, struct Token *token,
 			if (!if_not_exist) {
 				diag_set(ClientError, ER_INDEX_EXISTS_IN_SPACE,
 					 name, def->name);
-				sql_parser_error(parse);
+				parse->rc = SQL_TARANTOOL_ERROR;
 			}
 			goto exit_create_index;
 		}
@@ -2238,7 +2222,6 @@ sql_create_index(struct Parse *parse, struct Token *token,
 	if (tbl_name != NULL && space_is_system(space)) {
 		diag_set(ClientError, ER_MODIFY_INDEX, name, def->name,
 			 "can't create index on system space");
-		parse->nErr++;
 		parse->rc = SQL_TARANTOOL_ERROR;
 		goto exit_create_index;
 	}
@@ -2268,7 +2251,6 @@ sql_create_index(struct Parse *parse, struct Token *token,
 	if (index == NULL) {
 		diag_set(OutOfMemory, sizeof(*index), "region", "index");
 		parse->rc = SQL_TARANTOOL_ERROR;
-		parse->nErr++;
 		goto exit_create_index;
 	}
 	memset(index, 0, sizeof(*index));
@@ -2438,7 +2420,7 @@ sql_drop_index(struct Parse *parse_context, struct SrcList *index_name_list,
 	assert(v != NULL);
 	struct sql *db = parse_context->db;
 	/* Never called with prior errors. */
-	assert(parse_context->nErr == 0);
+	assert(parse_context->rc != SQL_TARANTOOL_ERROR);
 	assert(table_token != NULL);
 	const char *table_name = sqlNameFromToken(db, table_token);
 	if (db->mallocFailed) {
@@ -2451,7 +2433,7 @@ sql_drop_index(struct Parse *parse_context, struct SrcList *index_name_list,
 	if (space == NULL) {
 		if (!if_exists) {
 			diag_set(ClientError, ER_NO_SUCH_SPACE, table_name);
-			sql_parser_error(parse_context);
+			parse_context->rc = SQL_TARANTOOL_ERROR;
 		}
 		goto exit_drop_index;
 	}
@@ -2462,7 +2444,7 @@ sql_drop_index(struct Parse *parse_context, struct SrcList *index_name_list,
 		if (!if_exists) {
 			diag_set(ClientError, ER_NO_SUCH_INDEX_NAME,
 				 index_name, table_name);
-			sql_parser_error(parse_context);
+			parse_context->rc = SQL_TARANTOOL_ERROR;
 		}
 		goto exit_drop_index;
 	}
@@ -2820,7 +2802,7 @@ sqlSrcListAppendFromTerm(Parse * pParse,	/* Parsing context */
 	if (!p && (pOn || pUsing)) {
 		diag_set(ClientError, ER_SQL_SYNTAX, "FROM clause",
 			 "a JOIN clause is required before ON and USING");
-		sql_parser_error(pParse);
+		pParse->rc = SQL_TARANTOOL_ERROR;
 		goto append_from_error;
 	}
 	p = sqlSrcListAppend(db, p, pTable);
diff --git a/src/box/sql/callback.c b/src/box/sql/callback.c
index 4594cac..6c26402 100644
--- a/src/box/sql/callback.c
+++ b/src/box/sql/callback.c
@@ -50,7 +50,6 @@ sql_get_coll_seq(Parse *parser, const char *name, uint32_t *coll_id)
 	if (p == NULL) {
 		diag_set(ClientError, ER_NO_SUCH_COLLATION, name);
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return NULL;
 	} else {
 		*coll_id = p->id;
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index a7bf3b3..c582a10 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -43,7 +43,7 @@ sql_lookup_space(struct Parse *parse, struct SrcList_item *space_name)
 	struct space *space = space_by_name(space_name->zName);
 	if (space == NULL) {
 		diag_set(ClientError, ER_NO_SUCH_SPACE, space_name->zName);
-		sql_parser_error(parse);
+		parse->rc = SQL_TARANTOOL_ERROR;
 		return NULL;
 	}
 	assert(space != NULL);
@@ -51,7 +51,6 @@ sql_lookup_space(struct Parse *parse, struct SrcList_item *space_name)
 		diag_set(ClientError, ER_UNSUPPORTED, "SQL",
 			 "space without format");
 		parse->rc = SQL_TARANTOOL_ERROR;
-		parse->nErr++;
 		return NULL;
 	}
 	space_name->space = space;
@@ -94,7 +93,7 @@ sql_table_truncate(struct Parse *parse, struct SrcList *tab_list)
 	struct space *space = space_by_name(tab_name);
 	if (space == NULL) {
 		diag_set(ClientError, ER_NO_SUCH_SPACE, tab_name);
-		sql_parser_error(parse);
+		parse->rc = SQL_TARANTOOL_ERROR;
 	}
 	if (! rlist_empty(&space->parent_fk_constraint)) {
 		sqlErrorMsg(parse, "can not truncate space '%s' because other "
@@ -117,7 +116,7 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 		      struct Expr *where)
 {
 	struct sql *db = parse->db;
-	if (parse->nErr || db->mallocFailed)
+	if (parse->rc == SQL_TARANTOOL_ERROR || db->mallocFailed)
 		goto delete_from_cleanup;
 
 	assert(tab_list->nSrc == 1);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index c914cfb..e4924ac 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -254,10 +254,9 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_explicit_coll, uint32_t *coll_id,
 					 * several times: this
 					 * function is recursive.
 					 */
-					if (parse->nErr == 0) {
+					if (parse->rc != SQL_TARANTOOL_ERROR) {
 						diag_set(ClientError,
 							 ER_ILLEGAL_COLLATION_MIX);
-						parse->nErr++;
 						parse->rc = SQL_TARANTOOL_ERROR;
 					}
 					return -1;
@@ -411,7 +410,6 @@ sql_binary_compare_coll_seq(Parse *parser, Expr *left, Expr *right,
 	if (collations_check_compatibility(lhs_coll_id, is_lhs_forced,
 					   rhs_coll_id, is_rhs_forced, id) != 0) {
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return -1;
 	}
 	return 0;
@@ -821,7 +819,7 @@ exprSetHeight(Expr * p)
 void
 sqlExprSetHeightAndFlags(Parse * pParse, Expr * p)
 {
-	if (pParse->nErr)
+	if (pParse->rc == SQL_TARANTOOL_ERROR)
 		return;
 	exprSetHeight(p);
 	sqlExprCheckHeight(pParse, p->nHeight);
@@ -1005,7 +1003,7 @@ sqlPExpr(Parse * pParse,	/* Parsing context */
     )
 {
 	Expr *p;
-	if (op == TK_AND && pParse->nErr == 0) {
+	if (op == TK_AND && pParse->rc != SQL_TARANTOOL_ERROR) {
 		/* Take advantage of short-circuit false optimization for AND */
 		p = sqlExprAnd(pParse->db, pLeft, pRight);
 	} else {
@@ -2407,7 +2405,8 @@ sqlFindInIndex(Parse * pParse,	/* Parsing context */
 	 * satisfy the query.  This is preferable to generating a new
 	 * ephemeral table.
 	 */
-	if (pParse->nErr == 0 && (p = isCandidateForInOpt(pX)) != 0) {
+	if (pParse->rc != SQL_TARANTOOL_ERROR &&
+	    (p = isCandidateForInOpt(pX)) != 0) {
 		sql *db = pParse->db;	/* Database connection */
 		ExprList *pEList = p->pEList;
 		int nExpr = pEList->nExpr;
@@ -3041,8 +3040,9 @@ sqlExprCodeIN(Parse * pParse,	/* Parsing and code generating context */
 				   destIfFalse == destIfNull ? 0 : &rRhsHasNull,
 				   aiMap, 0);
 
-	assert(pParse->nErr || nVector == 1 || eType == IN_INDEX_EPH
-	       || eType == IN_INDEX_INDEX_ASC || eType == IN_INDEX_INDEX_DESC);
+	assert(pParse->rc == SQL_TARANTOOL_ERROR || nVector == 1 ||
+	       eType == IN_INDEX_EPH || eType == IN_INDEX_INDEX_ASC ||
+	       eType == IN_INDEX_INDEX_DESC);
 #ifdef SQL_DEBUG
 	/* Confirm that aiMap[] contains nVector integer values between 0 and
 	 * nVector-1.
@@ -3364,7 +3364,8 @@ sqlExprCacheStore(Parse * pParse, int iTab, int iCol, int iReg)
 	struct yColCache *p;
 
 	/* Unless an error has occurred, register numbers are always positive. */
-	assert(iReg > 0 || pParse->nErr || pParse->db->mallocFailed);
+	assert(iReg > 0 || pParse->rc == SQL_TARANTOOL_ERROR ||
+	       pParse->db->mallocFailed);
 	assert(iCol >= -1 && iCol < 32768);	/* Finite column numbers */
 
 	/* The SQL_ColumnCache flag disables the column cache.  This is used
@@ -3997,7 +3998,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			if (pDef == 0 || pDef->xFinalize != 0) {
 				diag_set(ClientError, ER_NO_SUCH_FUNCTION,
 					 zId);
-				sql_parser_error(pParse);
+				pParse->rc = SQL_TARANTOOL_ERROR;
 				break;
 			}
 
@@ -4341,8 +4342,9 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			} else {
 				sqlVdbeAddOp2(v, OP_Null, 0, target);
 			}
-			assert(pParse->db->mallocFailed || pParse->nErr > 0
-			       || pParse->iCacheLevel == iCacheLevel);
+			assert(pParse->db->mallocFailed ||
+			       pParse->rc == SQL_TARANTOOL_ERROR ||
+			       pParse->iCacheLevel == iCacheLevel);
 			sqlVdbeResolveLabel(v, endLabel);
 			break;
 		}
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 17fbdec..e8cdd39 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -277,7 +277,7 @@ sqlInsert(Parse * pParse,	/* Parser context */
 
 	db = pParse->db;
 	memset(&dest, 0, sizeof(dest));
-	if (pParse->nErr || db->mallocFailed) {
+	if (pParse->rc == SQL_TARANTOOL_ERROR || db->mallocFailed) {
 		goto insert_cleanup;
 	}
 
@@ -426,7 +426,7 @@ sqlInsert(Parse * pParse,	/* Parser context */
 		dest.nSdst = space_def->field_count;
 		rc = sqlSelect(pParse, pSelect, &dest);
 		regFromSelect = dest.iSdst;
-		if (rc || db->mallocFailed || pParse->nErr)
+		if (rc || db->mallocFailed || pParse->rc == SQL_TARANTOOL_ERROR)
 			goto insert_cleanup;
 		sqlVdbeEndCoroutine(v, regYield);
 		sqlVdbeJumpHere(v, addrTop - 1);	/* label B: */
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 67a7a57..ac50731 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -38,11 +38,11 @@
   } else {
     diag_set(ClientError, ER_SQL_SYNTAX_NEAR, TOKEN.n, TOKEN.z);
   }
-  sql_parser_error(pParse);
+  pParse->rc = SQL_TARANTOOL_ERROR;
 }
 %stack_overflow {
   diag_set(ClientError, ER_SQL_STACK_OVERFLOW);
-  sql_parser_error(pParse);
+  pParse->rc = SQL_TARANTOOL_ERROR;
 }
 
 // The name of the generated procedure that implements the parser
@@ -118,7 +118,7 @@ ecmd ::= explain cmdx SEMI. {
 }
 ecmd ::= SEMI. {
   diag_set(ClientError, ER_SQL_STATEMENT_EMPTY);
-  sql_parser_error(pParse);
+  pParse->rc = SQL_TARANTOOL_ERROR;
 }
 explain ::= .
 explain ::= EXPLAIN.              { pParse->explain = 1; }
@@ -232,7 +232,7 @@ columnname(A) ::= nm(A) typedef(Y). {sqlAddColumn(pParse,&A,&Y);}
 nm(A) ::= id(A). {
   if(A.isReserved) {
     diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, A.n, A.z, A.n, A.z);
-    sql_parser_error(pParse);
+    pParse->rc = SQL_TARANTOOL_ERROR;
   }
 }
 
@@ -904,7 +904,7 @@ expr(A) ::= VARIABLE(X).     {
     spanExpr(&A, pParse, TK_VARIABLE, X);
     if (A.pExpr->u.zToken[0] == '?' && n > 1) {
       diag_set(ClientError, ER_SQL_SYNTAX_NEAR, t.n, t.z);
-      sql_parser_error(pParse);
+      pParse->rc = SQL_TARANTOOL_ERROR;
     } else {
       sqlExprAssignVarNumber(pParse, A.pExpr, n);
     }
@@ -912,7 +912,7 @@ expr(A) ::= VARIABLE(X).     {
     assert( t.n>=2 );
     spanSet(&A, &t, &t);
     diag_set(ClientError, ER_SQL_SYNTAX_NEAR, t.n, t.z);
-    sql_parser_error(pParse);
+    pParse->rc = SQL_TARANTOOL_ERROR;
     A.pExpr = NULL;
   }
 }
@@ -1384,13 +1384,13 @@ tridxby ::= .
 tridxby ::= INDEXED BY nm. {
   diag_set(ClientError, ER_SQL_SYNTAX, "trigger body", "the INDEXED BY clause "\
            "is not allowed on UPDATE or DELETE statements within triggers");
-  sql_parser_error(pParse);
+  pParse->rc = SQL_TARANTOOL_ERROR;
 }
 tridxby ::= NOT INDEXED. {
   diag_set(ClientError, ER_SQL_SYNTAX, "trigger body", "the NOT INDEXED "\
            "clause is not allowed on UPDATE or DELETE statements within "\
            "triggers");
-  sql_parser_error(pParse);
+  pParse->rc = SQL_TARANTOOL_ERROR;
 }
 
 
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index a7224f5..b555c06 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -469,7 +469,7 @@ sqlPragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 	pPragma = pragmaLocate(zLeft);
 	if (pPragma == 0) {
 		diag_set(ClientError, ER_SQL_NO_SUCH_PRAGMA, zLeft);
-		sql_parser_error(pParse);
+		pParse->rc = SQL_TARANTOOL_ERROR;
 		goto pragma_out;
 	}
 	/* Register the result column names for pragmas that return results */
@@ -537,7 +537,6 @@ sqlPragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 		iter = box_index_iterator(space->def->id, 0,ITER_ALL, key_buf, key_end);
 		if (iter == NULL) {
 			pParse->rc = SQL_TARANTOOL_ERROR;
-			pParse->nErr++;
 			goto pragma_out;
 		}
 		int rc = box_iterator_next(iter, &tuple);
@@ -623,12 +622,10 @@ sqlPragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			diag_set(ClientError, ER_ILLEGAL_PARAMS,
 				 "string value is expected");
 			pParse->rc = SQL_TARANTOOL_ERROR;
-			pParse->nErr++;
 			goto pragma_out;
 		}
 		if (sql_default_engine_set(zRight) != 0) {
 			pParse->rc = SQL_TARANTOOL_ERROR;
-			pParse->nErr++;
 			goto pragma_out;
 		}
 		sqlVdbeAddOp0(v, OP_Expire);
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 1339157..0b3d876 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -441,7 +441,7 @@ lookupName(Parse * pParse,	/* The parsing context */
 			diag_set(ClientError, ER_NO_SUCH_FIELD_NAME, zCol,
 				 zTab);
 		}
-		sql_parser_error(pParse);
+		pParse->rc = SQL_TARANTOOL_ERROR;
 		pTopNC->nErr++;
 	}
 
@@ -707,7 +707,7 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 #endif
 			    ) {
 				diag_set(ClientError, ER_NO_SUCH_FUNCTION, zId);
-				sql_parser_error(pParse);
+				pParse->rc = SQL_TARANTOOL_ERROR;
 				pNC->nErr++;
 			} else if (wrong_num_args) {
 				sqlErrorMsg(pParse,
@@ -809,7 +809,7 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 			break;
 		}
 	}
-	return (pParse->nErr
+	return (pParse->rc == SQL_TARANTOOL_ERROR
 		|| pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
 }
 
@@ -1195,7 +1195,7 @@ resolveSelectStep(Walker * pWalker, Select * p)
 	 */
 	if ((p->selFlags & SF_Expanded) == 0) {
 		sqlSelectPrep(pParse, p, pOuterNC);
-		return (pParse->nErr
+		return (pParse->rc == SQL_TARANTOOL_ERROR
 			|| db->mallocFailed) ? WRC_Abort : WRC_Prune;
 	}
 
@@ -1252,7 +1252,8 @@ resolveSelectStep(Walker * pWalker, Select * p)
 				sqlResolveSelectNames(pParse,
 							  pItem->pSelect,
 							  pOuterNC);
-				if (pParse->nErr || db->mallocFailed)
+				if (pParse->rc == SQL_TARANTOOL_ERROR ||
+				    db->mallocFailed)
 					return WRC_Abort;
 
 				for (pNC = pOuterNC; pNC; pNC = pNC->pNext)
@@ -1529,7 +1530,7 @@ sqlResolveExprNames(NameContext * pNC,	/* Namespace to resolve expressions in. *
 #if SQL_MAX_EXPR_DEPTH>0
 	pNC->pParse->nHeight -= pExpr->nHeight;
 #endif
-	if (pNC->nErr > 0 || w.pParse->nErr > 0) {
+	if (pNC->nErr > 0 || w.pParse->rc == SQL_TARANTOOL_ERROR) {
 		ExprSetProperty(pExpr, EP_Error);
 	}
 	if (pNC->ncFlags & NC_HasAgg) {
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 7eea90e..3249db6 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -196,13 +196,13 @@ sqlSelectNew(Parse * pParse,	/* Parsing context */
 	pNew->pLimit = pLimit;
 	pNew->pOffset = pOffset;
 	pNew->pWith = 0;
-	assert(pOffset == 0 || pLimit != 0 || pParse->nErr > 0
+	assert(pOffset == 0 || pLimit != 0 || pParse->rc == SQL_TARANTOOL_ERROR
 	       || db->mallocFailed != 0);
 	if (db->mallocFailed) {
 		clearSelect(db, pNew, pNew != &standin);
 		pNew = 0;
 	} else {
-		assert(pNew->pSrc != 0 || pParse->nErr > 0);
+		assert(pNew->pSrc != 0 || pParse->rc == SQL_TARANTOOL_ERROR);
 	}
 	assert(pNew != &standin);
 	return pNew;
@@ -2003,7 +2003,7 @@ sqlResultSetOfSelect(Parse * pParse, Select * pSelect)
 	user_session->sql_flags |= ~SQL_FullColNames;
 	user_session->sql_flags &= SQL_ShortColNames;
 	sqlSelectPrep(pParse, pSelect, 0);
-	if (pParse->nErr)
+	if (pParse->rc == SQL_TARANTOOL_ERROR)
 		return NULL;
 	while (pSelect->pPrior)
 		pSelect = pSelect->pPrior;
@@ -2094,7 +2094,7 @@ computeLimitRegisters(Parse * pParse, Select * p, int iBreak)
 		   (p->pOffset->flags & EP_Collate) != 0)) {
 			diag_set(ClientError, ER_SQL_SYNTAX_NEAR,
 				 sizeof("COLLATE"), "COLLATE");
-			sql_parser_error(pParse);
+			pParse->rc = SQL_TARANTOOL_ERROR;
 			return;
 		}
 		p->iLimit = iLimit = ++pParse->nMem;
@@ -2236,7 +2236,6 @@ multi_select_coll_seq_r(struct Parse *parser, struct Select *p, int n,
 					   current_coll_id, is_current_forced,
 					   &res_coll_id) != 0) {
 		parser->rc = SQL_TARANTOOL_ERROR;
-		parser->nErr++;
 		return 0;
 	}
 	*is_forced_coll = (is_prior_forced || is_current_forced);
@@ -3115,7 +3114,8 @@ generateOutputSubroutine(struct Parse *parse, struct Select *p,
 		 * of the scan loop.
 		 */
 	case SRT_Mem:{
-			assert(in->nSdst == 1 || parse->nErr > 0);
+			assert(in->nSdst == 1 ||
+			       parse->rc == SQL_TARANTOOL_ERROR);
 			testcase(in->nSdst != 1);
 			sqlExprCodeMove(parse, in->iSdst, dest->iSDParm,
 					    1);
@@ -3585,7 +3585,7 @@ multiSelectOrderBy(Parse * pParse,	/* Parsing context */
   *** subqueries ***
   */
 	explainComposite(pParse, p->op, iSub1, iSub2, 0);
-	return pParse->nErr != 0;
+	return pParse->rc == SQL_TARANTOOL_ERROR;
 }
 #endif
 
@@ -4428,7 +4428,7 @@ sqlIndexedByLookup(Parse * pParse, struct SrcList_item *pFrom)
 		if (idx == NULL) {
 			diag_set(ClientError, ER_NO_SUCH_INDEX_NAME,
 				 zIndexedBy, space->def->name);
-			sql_parser_error(pParse);
+			pParse->rc = SQL_TARANTOOL_ERROR;
 			return SQL_ERROR;
 		}
 		pFrom->pIBIndex = idx->def;
@@ -5055,7 +5055,7 @@ selectExpander(Walker * pWalker, Select * p)
 						diag_set(ClientError,
 							 ER_SQL_SELECT_WILDCARD);
 					}
-					sql_parser_error(pParse);
+					pParse->rc = SQL_TARANTOOL_ERROR;
 				}
 			}
 		}
@@ -5097,7 +5097,7 @@ sqlExprWalkNoop(Walker * NotUsed, Expr * NotUsed2)
  * name resolution is performed.
  *
  * If anything goes wrong, an error message is written into pParse.
- * The calling function can detect the problem by looking at pParse->nErr
+ * The calling function can detect the problem by looking at pParse->rc
  * and/or pParse->db->mallocFailed.
  */
 static void
@@ -5206,10 +5206,10 @@ sqlSelectPrep(Parse * pParse,	/* The parser context */
 	if (p->selFlags & SF_HasTypeInfo)
 		return;
 	sqlSelectExpand(pParse, p);
-	if (pParse->nErr || db->mallocFailed)
+	if (pParse->rc == SQL_TARANTOOL_ERROR || db->mallocFailed)
 		return;
 	sqlResolveSelectNames(pParse, p, pOuterNC);
-	if (pParse->nErr || db->mallocFailed)
+	if (pParse->rc == SQL_TARANTOOL_ERROR || db->mallocFailed)
 		return;
 	sqlSelectAddTypeInfo(pParse, p);
 }
@@ -5464,7 +5464,7 @@ sqlSelect(Parse * pParse,		/* The parser context */
 	pParse->iSelectId = pParse->iNextSelectId++;
 
 	db = pParse->db;
-	if (p == 0 || db->mallocFailed || pParse->nErr) {
+	if (p == 0 || db->mallocFailed || pParse->rc == SQL_TARANTOOL_ERROR) {
 		return 1;
 	}
 	memset(&sAggInfo, 0, sizeof(sAggInfo));
@@ -5499,7 +5499,7 @@ sqlSelect(Parse * pParse,		/* The parser context */
 	memset(&sSort, 0, sizeof(sSort));
 	sSort.pOrderBy = p->pOrderBy;
 	pTabList = p->pSrc;
-	if (pParse->nErr || db->mallocFailed) {
+	if (pParse->rc == SQL_TARANTOOL_ERROR || db->mallocFailed) {
 		goto select_end;
 	}
 	assert(p->pEList != 0);
@@ -6393,7 +6393,7 @@ sqlSelect(Parse * pParse,		/* The parser context */
 	/* The SELECT has been coded. If there is an error in the Parse structure,
 	 * set the return code to 1. Otherwise 0.
 	 */
-	rc = (pParse->nErr > 0);
+	rc = (pParse->rc == SQL_TARANTOOL_ERROR);
 
 	/* Control jumps to here if an error is encountered above, or upon
 	 * successful coding of the SELECT.
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 1a28f1a..be0e94e 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2665,7 +2665,6 @@ struct Parse {
 	u8 nColCache;		/* Number of entries in aColCache[] */
 	int nRangeReg;		/* Size of the temporary register block */
 	int iRangeReg;		/* First register in temporary register block */
-	int nErr;		/* Number of errors seen */
 	int nTab;		/* Number of previously allocated VDBE cursors */
 	int nMem;		/* Number of memory cells used so far */
 	int nOpAlloc;		/* Number of slots allocated for Vdbe.aOp[] */
@@ -3223,14 +3222,6 @@ int sqlKeywordCode(const unsigned char *, int);
 int sqlRunParser(Parse *, const char *);
 
 /**
- * Increment error counter.
- *
- * @param parse_context Current parsing context.
- */
-void
-sql_parser_error(struct Parse *parse_context);
-
-/**
  * This routine is called after a single SQL statement has been
  * parsed and a VDBE program to execute that statement has been
  * prepared.  This routine puts the finishing touches on the
diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
index 5ea0ea5..fe2c0ab 100644
--- a/src/box/sql/tokenize.c
+++ b/src/box/sql/tokenize.c
@@ -508,7 +508,7 @@ sqlRunParser(Parse * pParse, const char *zSql)
 				diag_set(ClientError, ER_SQL_UNKNOWN_TOKEN,
 					 pParse->sLastToken.n,
 					 pParse->sLastToken.z);
-				sql_parser_error(pParse);
+				pParse->rc = SQL_TARANTOOL_ERROR;
 				break;
 			}
 		} else {
@@ -532,7 +532,7 @@ sqlRunParser(Parse * pParse, const char *zSql)
 	}
 	if (pParse->rc != SQL_OK && pParse->rc != SQL_DONE)
 		nErr++;
-	if (pParse->pVdbe != NULL && pParse->nErr > 0) {
+	if (pParse->pVdbe != NULL && pParse->rc == SQL_TARANTOOL_ERROR) {
 		sqlVdbeDelete(pParse->pVdbe);
 		pParse->pVdbe = 0;
 	}
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index 4c7ab8a..89d42d1 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -155,7 +155,6 @@ sql_trigger_begin(struct Parse *parse, struct Token *name, int tr_tm,
 
 set_tarantool_error_and_cleanup:
 	parse->rc = SQL_TARANTOOL_ERROR;
-	parse->nErr++;
 	goto trigger_cleanup;
 }
 
@@ -169,7 +168,7 @@ sql_trigger_finish(struct Parse *parse, struct TriggerStep *step_list,
 	struct sql *db = parse->db;
 
 	parse->parsed_ast.trigger = NULL;
-	if (NEVER(parse->nErr) || trigger == NULL)
+	if (NEVER(parse->rc == SQL_TARANTOOL_ERROR) || trigger == NULL)
 		goto cleanup;
 	char *trigger_name = trigger->zName;
 	trigger->step_list = step_list;
@@ -722,20 +721,6 @@ onErrorText(int onError)
 }
 #endif
 
-/*
- * Parse context structure pFrom has just been used to create a sub-vdbe
- * (trigger program). If an error has occurred, transfer error information
- * from pFrom to pTo.
- */
-static void
-transferParseError(Parse * pTo, Parse * pFrom)
-{
-	if (pTo->nErr == 0) {
-		pTo->nErr = pFrom->nErr;
-		pTo->rc = pFrom->rc;
-	}
-}
-
 /**
  * Create and populate a new TriggerPrg object with a sub-program
  * implementing trigger pTrigger with ON CONFLICT policy orconf.
@@ -844,7 +829,7 @@ sql_row_trigger_program(struct Parse *parser, struct sql_trigger *trigger,
 		VdbeComment((v, "End: %s.%s", trigger->zName,
 			     onErrorText(orconf)));
 
-		transferParseError(parser, pSubParse);
+		parser->rc = pSubParse->rc;
 		if (db->mallocFailed == 0) {
 			pProgram->aOp =
 			    sqlVdbeTakeOpArray(v, &pProgram->nOp,
@@ -918,7 +903,7 @@ vdbe_code_row_trigger_direct(struct Parse *parser, struct sql_trigger *trigger,
 	struct Vdbe *v = sqlGetVdbe(parser);
 
 	TriggerPrg *pPrg = sql_row_trigger(parser, trigger, space, orconf);
-	assert(pPrg != NULL || parser->nErr != 0 ||
+	assert(pPrg != NULL || parser->rc == SQL_TARANTOOL_ERROR ||
 	       parser->db->mallocFailed != 0);
 
 	/*
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 670e547..40d16ac 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -116,7 +116,7 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 	int upd_cols_cnt = 0;
 
 	db = pParse->db;
-	if (pParse->nErr || db->mallocFailed) {
+	if (pParse->rc == SQL_TARANTOOL_ERROR || db->mallocFailed) {
 		goto update_cleanup;
 	}
 	assert(pTabList->nSrc == 1);
@@ -192,7 +192,7 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 		if (j >= (int)def->field_count) {
 			diag_set(ClientError, ER_NO_SUCH_FIELD_NAME,
 				 pChanges->a[i].zName, def->name);
-			sql_parser_error(pParse);
+			pParse->rc = SQL_TARANTOOL_ERROR;
 			goto update_cleanup;
 		}
 	}
diff --git a/src/box/sql/util.c b/src/box/sql/util.c
index e4c93cb..4f7e36a 100644
--- a/src/box/sql/util.c
+++ b/src/box/sql/util.c
@@ -238,17 +238,9 @@ sqlErrorMsg(Parse * pParse, const char *zFormat, ...)
 	va_end(ap);
 	diag_set(ClientError, ER_SQL_PARSER_GENERIC, zMsg);
 	sqlDbFree(db, zMsg);
-	pParse->nErr++;
 	pParse->rc = SQL_TARANTOOL_ERROR;
 }
 
-void
-sql_parser_error(struct Parse *parse_context)
-{
-	parse_context->nErr++;
-	parse_context->rc = SQL_TARANTOOL_ERROR;
-}
-
 /*
  * Convert an SQL-style quoted string into a normal string by removing
  * the quote characters.  The conversion is done in-place.  If the
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index 1bba9d6..28a19f0 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -2805,7 +2805,6 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder,	/* WHERE clause information */
 		struct key_def *key_def = key_def_new(&part, 1);
 		if (key_def == NULL) {
 tnt_error:
-			pWInfo->pParse->nErr++;
 			pWInfo->pParse->rc = SQL_TARANTOOL_ERROR;
 			return SQL_TARANTOOL_ERROR;
 		}
@@ -4464,7 +4463,7 @@ sqlWhereBegin(Parse * pParse,	/* The parser context */
 	    (user_session->sql_flags & SQL_ReverseOrder) != 0) {
 		pWInfo->revMask = ALLBITS;
 	}
-	if (pParse->nErr || NEVER(db->mallocFailed)) {
+	if (pParse->rc == SQL_TARANTOOL_ERROR || NEVER(db->mallocFailed)) {
 		goto whereBeginError;
 	}
 #ifdef WHERETRACE_ENABLED
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 04b79ab..0360f40 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -1473,8 +1473,9 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 				    sqlWhereBegin(pParse, pOrTab, pOrExpr,
 						      0, 0, wctrlFlags,
 						      iCovCur);
-				assert(pSubWInfo || pParse->nErr
-				       || db->mallocFailed);
+				assert(pSubWInfo ||
+				       pParse->rc == SQL_TARANTOOL_ERROR ||
+				       db->mallocFailed);
 				if (pSubWInfo) {
 					WhereLoop *pSubLoop;
 					int addrExplain =
-- 
2.7.4

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

* [tarantool-patches] Re: [PATCH v2 1/5] sql: remove "syntax error after column name" error
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error imeevma
@ 2019-02-25 19:34   ` n.pettik
  2019-02-27 11:32   ` Kirill Yukhin
  1 sibling, 0 replies; 21+ messages in thread
From: n.pettik @ 2019-02-25 19:34 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen


> On 25 Feb 2019, at 20:14, imeevma@tarantool.org wrote:
> 
> Error "syntax error after column name" does not make any sense.
> Let's remove it.
> 
> Part of #3965
> —

This one is LGTM.

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

* [tarantool-patches] Re: [PATCH v2 2/5] sql: rework syntax errors
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 2/5] sql: rework syntax errors imeevma
@ 2019-02-25 20:02   ` n.pettik
  2019-02-26  8:24     ` Konstantin Osipov
  0 siblings, 1 reply; 21+ messages in thread
From: n.pettik @ 2019-02-25 20:02 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen



> On 25 Feb 2019, at 20:14, imeevma@tarantool.org wrote:
> 
> This patch reworks SQL syntax errors. After this patch, these
> error will be set as Tarantool errors.
> 
> Part of #3965
> ---
> src/box/errcode.h                          |  7 +++++
> src/box/sql/build.c                        |  6 ++---
> src/box/sql/parse.y                        | 41 ++++++++++++++++++------------
> src/box/sql/select.c                       | 11 ++++----
> src/box/sql/tokenize.c                     |  7 ++---
> test/box/misc.result                       |  6 +++++
> test/sql-tap/alter2.test.lua               |  4 +--
> test/sql-tap/blob.test.lua                 | 20 +++++++--------
> test/sql-tap/check.test.lua                | 10 ++++----
> test/sql-tap/colname.test.lua              |  2 +-
> test/sql-tap/count.test.lua                |  2 +-
> test/sql-tap/default.test.lua              |  4 +--
> test/sql-tap/e_select1.test.lua            | 18 ++++++-------
> test/sql-tap/gh-2367-pragma.test.lua       |  4 +--
> test/sql-tap/gh2168-temp-tables.test.lua   |  4 +--
> test/sql-tap/identifier_case.test.lua      |  2 +-
> test/sql-tap/index-info.test.lua           |  2 +-
> test/sql-tap/index1.test.lua               |  2 +-
> test/sql-tap/index7.test.lua               |  2 +-
> test/sql-tap/join.test.lua                 |  2 +-
> test/sql-tap/keyword1.test.lua             |  2 +-
> test/sql-tap/misc1.test.lua                |  8 +++---
> test/sql-tap/misc5.test.lua                |  6 ++---
> test/sql-tap/null.test.lua                 |  8 +++---
> test/sql-tap/select1.test.lua              | 20 +++++++--------
> test/sql-tap/select3.test.lua              |  4 +--
> test/sql-tap/start-transaction.test.lua    | 14 +++++-----
> test/sql-tap/table.test.lua                | 10 ++++----
> test/sql-tap/tkt3935.test.lua              | 14 +++++-----
> test/sql-tap/tokenize.test.lua             | 26 +++++++++----------
> test/sql-tap/trigger1.test.lua             | 14 +++++-----
> test/sql-tap/view.test.lua                 |  4 +--
> test/sql-tap/with1.test.lua                |  6 ++---
> test/sql-tap/with2.test.lua                | 18 ++++++-------
> test/sql/checks.result                     |  2 +-
> test/sql/collation.result                  | 12 ++++-----
> test/sql/foreign-keys.result               | 10 +++++---
> test/sql/gh-3888-values-blob-assert.result |  8 +++---
> test/sql/iproto.result                     | 10 ++++----
> test/sql/misc.result                       | 14 +++++-----
> test/sql/on-conflict.result                | 16 ++++++------
> test/sql/types.result                      | 13 ++++++----
> 42 files changed, 213 insertions(+), 182 deletions(-)
> 
> diff --git a/src/box/errcode.h b/src/box/errcode.h
> index a1fcf01..6546b2f 100644
> --- a/src/box/errcode.h
> +++ b/src/box/errcode.h
> @@ -231,6 +231,13 @@ struct errcode_record {
> 	/*176 */_(ER_SQL_CANT_RESOLVE_FIELD,	"Can’t resolve field '%s'") \
> 	/*177 */_(ER_INDEX_EXISTS_IN_SPACE,	"Index '%s' already exists in space '%s'") \
> 	/*178 */_(ER_INCONSISTENT_TYPES,	"Inconsistent types: expected %s got %s") \
> +	/*179 */_(ER_SQL_SYNTAX,		"Syntax error in %s: %s") \
> +	/*180 */_(ER_SQL_STACK_OVERFLOW,	"Failed to parse SQL statement: parser stack limit reached") \
> +	/*181 */_(ER_SQL_SELECT_WILDCARD,	"Failed to expand '*' in SELECT statement without FROM clause") \
> +	/*182 */_(ER_SQL_STATEMENT_EMPTY,	"Failed to execute an empty SQL statement") \
> +	/*183 */_(ER_SQL_KEYWORD_IS_RESERVED,	"Keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
> +	/*184 */_(ER_SQL_SYNTAX_NEAR,		"Unrecognized syntax near '%.*s'") \

Quite strange name for err code.
I’d rather say ER_SQL_UNRECOGNIZED_SYMBOL/SYNTAX.
Is this message suggested by Konstantin? To be honest, I would
prefer old one. “Unrecognized syntax” doesn’t sound good and clear enough,
at least for me. Personally I would say “Syntax error near %s”.
The last one is used in several DBs, so I suppose it is common way to raise
errors like that.

> diff --git a/test/sql-tap/alter2.test.lua b/test/sql-tap/alter2.test.lua
> index e219a36..ef57955 100755
> --- a/test/sql-tap/alter2.test.lua
> +++ b/test/sql-tap/alter2.test.lua
> @@ -223,7 +223,7 @@ test:do_catchsql_test(
>         ALTER TABLE child ADD CONSTRAINT fk FOREIGN KEY REFERENCES child(id);
>     ]], {
>         -- <alter2-4.1>
> -        1, "near \"REFERENCES\": syntax error"
> +        1, "Unrecognized syntax near 'REFERENCES'"
>         -- </alter2-4.1>
>     })

The rest is obvious and OK.

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

* [tarantool-patches] Re: [PATCH v2 3/5] sql: save SQL parser errors in diag_set()
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 3/5] sql: save SQL parser errors in diag_set() imeevma
@ 2019-02-25 23:01   ` n.pettik
  2019-02-26  8:25     ` Konstantin Osipov
  2019-02-26 15:29     ` Imeev Mergen
  0 siblings, 2 replies; 21+ messages in thread
From: n.pettik @ 2019-02-25 23:01 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen



> On 25 Feb 2019, at 20:14, imeevma@tarantool.org wrote:
> 
> After this patch all SQL parser errors will be saved in diag_set()
> instead of field zErrMsg of struct Parse.
> 
> Part of #3965
> ---
> src/box/errcode.h           | 1 +
> src/box/sql/build.c         | 3 ++-
> src/box/sql/util.c          | 6 +++---
> test/box/misc.result        | 1 +
> test/sql-tap/check.test.lua | 2 +-
> test/sql/triggers.result    | 4 ++--
> 6 files changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/src/box/errcode.h b/src/box/errcode.h
> index 6546b2f..779d927 100644
> --- a/src/box/errcode.h
> +++ b/src/box/errcode.h
> @@ -238,6 +238,7 @@ struct errcode_record {
> 	/*183 */_(ER_SQL_KEYWORD_IS_RESERVED,	"Keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
> 	/*184 */_(ER_SQL_SYNTAX_NEAR,		"Unrecognized syntax near '%.*s'") \
> 	/*185 */_(ER_SQL_UNKNOWN_TOKEN,		"Syntax error: unrecognized token: '%.*s'") \
> +	/*186 */_(ER_SQL_PARSER_GENERIC,	"%s") \

Hmm, what is this?

> /*
>  * !IMPORTANT! Please follow instructions at start of the file
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index f112c9f..deb5b89 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -194,7 +194,8 @@ sql_finish_coding(struct Parse *parse_context)
> 		sqlVdbeMakeReady(v, parse_context);
> 		parse_context->rc = SQL_DONE;
> 	} else {
> -		parse_context->rc = SQL_ERROR;
> +		if (parse_context->rc != SQL_TARANTOOL_ERROR)
> +			parse_context->rc = SQL_ERROR;

What a mess, explain this please.

> 	}
> }
> /**
> diff --git a/src/box/sql/util.c b/src/box/sql/util.c
> index c89e2e8..e4c93cb 100644
> --- a/src/box/sql/util.c
> +++ b/src/box/sql/util.c
> @@ -236,10 +236,10 @@ sqlErrorMsg(Parse * pParse, const char *zFormat, ...)
> 	va_start(ap, zFormat);
> 	zMsg = sqlVMPrintf(db, zFormat, ap);
> 	va_end(ap);
> +	diag_set(ClientError, ER_SQL_PARSER_GENERIC, zMsg);
> +	sqlDbFree(db, zMsg);
> 	pParse->nErr++;
> -	sqlDbFree(db, pParse->zErrMsg);
> -	pParse->zErrMsg = zMsg;
> -	pParse->rc = SQL_ERROR;
> +	pParse->rc = SQL_TARANTOOL_ERROR;
> }

Ok, so you decided to push all errors in one heap.
That’s definitely not what we discussed earlier.
Konstantin asked you to move each independent error
in a separate error code (and I agree with him to a lesser
or greater extent). Well, at least group them to semantic/
syntax groups. And instead you simply do this.
Then, I don’t understand purpose of all previous patches.

Am I missing something?

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

* [tarantool-patches] Re: [PATCH v2 2/5] sql: rework syntax errors
  2019-02-25 20:02   ` [tarantool-patches] " n.pettik
@ 2019-02-26  8:24     ` Konstantin Osipov
  2019-02-26 12:59       ` n.pettik
  2019-02-26 15:59       ` Imeev Mergen
  0 siblings, 2 replies; 21+ messages in thread
From: Konstantin Osipov @ 2019-02-26  8:24 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen

* n.pettik <korablev@tarantool.org> [19/02/25 23:05]:
> Quite strange name for err code.
> I’d rather say ER_SQL_UNRECOGNIZED_SYMBOL/SYNTAX.
> Is this message suggested by Konstantin? To be honest, I would
> prefer old one. “Unrecognized syntax” doesn’t sound good and clear enough,
> at least for me. Personally I would say “Syntax error near %s”.
> The last one is used in several DBs, so I suppose it is common way to raise
> errors like that.

Yes, the name is suggested by me. There is a name clash with a
generic ER_SYNTAX_ERROR. I also requested to add line/character
numbers to the error message, which I don't see in the patch. 

Mergen, did you find that this is not possible to do?


-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

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

* [tarantool-patches] Re: [PATCH v2 3/5] sql: save SQL parser errors in diag_set()
  2019-02-25 23:01   ` [tarantool-patches] " n.pettik
@ 2019-02-26  8:25     ` Konstantin Osipov
  2019-02-26 15:29     ` Imeev Mergen
  1 sibling, 0 replies; 21+ messages in thread
From: Konstantin Osipov @ 2019-02-26  8:25 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen

* n.pettik <korablev@tarantool.org> [19/02/26 10:06]:
> > +	/*186 */_(ER_SQL_PARSER_GENERIC,	"%s") \
> 
> Hmm, what is this?

This is a catch-all for all the errors we don't have time to
classify and prettify now. I suggested the same approach for all
the remaining sqlite errors: add a few catch-all tarantool error
codes which we will refine and deprecate after box.sql.execute()
removal is in.

Let's not forget the original patch that triggered this
refactoring, I want to push it asap as well.


-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

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

* [tarantool-patches] Re: [PATCH v2 5/5] sql: remove field nErr of struct Parse
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 5/5] sql: remove field nErr " imeevma
@ 2019-02-26  8:27   ` Konstantin Osipov
  2019-02-26 14:48   ` n.pettik
  1 sibling, 0 replies; 21+ messages in thread
From: Konstantin Osipov @ 2019-02-26  8:27 UTC (permalink / raw)
  To: tarantool-patches; +Cc: korablev

* imeevma@tarantool.org <imeevma@tarantool.org> [19/02/25 20:16]:
> At the moment, the only purpose of the field nErr of struct Parse
> is to show whether the field rc of the same struct is
> SQL_TARANTOOL_ERROR RC or not. Let's remove it.

Generally, the entire stack is looking good. 

Nikita, whatever you find, please let's do it in a separate
patchset, or please fix the issues yourself before pushing.


-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

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

* [tarantool-patches] Re: [PATCH v2 2/5] sql: rework syntax errors
  2019-02-26  8:24     ` Konstantin Osipov
@ 2019-02-26 12:59       ` n.pettik
  2019-02-26 13:12         ` Konstantin Osipov
  2019-02-26 15:59       ` Imeev Mergen
  1 sibling, 1 reply; 21+ messages in thread
From: n.pettik @ 2019-02-26 12:59 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen, Konstantin Osipov



> On 26 Feb 2019, at 11:24, Konstantin Osipov <kostja@tarantool.org> wrote:
> 
> * n.pettik <korablev@tarantool.org> [19/02/25 23:05]:
>> Quite strange name for err code.
>> I’d rather say ER_SQL_UNRECOGNIZED_SYMBOL/SYNTAX.
>> Is this message suggested by Konstantin? To be honest, I would
>> prefer old one. “Unrecognized syntax” doesn’t sound good and clear enough,
>> at least for me. Personally I would say “Syntax error near %s”.
>> The last one is used in several DBs, so I suppose it is common way to raise
>> errors like that.
> 
> Yes, the name is suggested by me. There is a name clash with a
> generic ER_SYNTAX_ERROR.

I don’t see problem here. First error is “Syntax error in %s : %s”.
For instance, “Syntax error in trigger body : blah-blah”.
Second one is “Syntax error near %s” or “Syntax error near %s token”.
For instance, “Syntax error near “create” token.”
Ok, if you still want to use ’syntax’ word, then at least let’s use
this variant: “Incorrect syntax near %s"

I failed to find any compiler or db which generate
“Unrecognized syntax …” error messages.

> I also requested to add line/character
> numbers to the error message, which I don't see in the patch.

Line is useless now, we don’t have multi-line processing.

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

* [tarantool-patches] Re: [PATCH v2 2/5] sql: rework syntax errors
  2019-02-26 12:59       ` n.pettik
@ 2019-02-26 13:12         ` Konstantin Osipov
  0 siblings, 0 replies; 21+ messages in thread
From: Konstantin Osipov @ 2019-02-26 13:12 UTC (permalink / raw)
  To: n.pettik; +Cc: tarantool-patches, Imeev Mergen

* n.pettik <korablev@tarantool.org> [19/02/26 16:02]:
> > Yes, the name is suggested by me. There is a name clash with a
> > generic ER_SYNTAX_ERROR.
> 
> I don’t see problem here. First error is “Syntax error in %s : %s”.
> For instance, “Syntax error in trigger body : blah-blah”.
> Second one is “Syntax error near %s” or “Syntax error near %s token”.
> For instance, “Syntax error near “create” token.”
> Ok, if you still want to use ’syntax’ word, then at least let’s use
> this variant: “Incorrect syntax near %s"
> 
> I failed to find any compiler or db which generate
> “Unrecognized syntax …” error messages.

Ok, if you ask me what's better - syntax error vs. unrecognized
syntax - up to you, it doesn't really matter.

Let's ensure two properties:
- the grammar and punctuation are correct
- the message is as specific as possible, i.e. allows the user to
  easily identify location of the error. Don't assume there is a
  single-line statement, assume 1 select statement can easily be
  200 lines of highly nested code.

> 
> > I also requested to add line/character
> > numbers to the error message, which I don't see in the patch.
> 
> Line is useless now, we don’t have multi-line processing.

We do.

tarantool> box.sql.execute("select\n\n\n1")
---
- - [1]
...


-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

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

* [tarantool-patches] Re: [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse imeevma
@ 2019-02-26 14:47   ` n.pettik
  2019-02-26 15:36     ` Imeev Mergen
  0 siblings, 1 reply; 21+ messages in thread
From: n.pettik @ 2019-02-26 14:47 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen


> diff --git a/src/box/sql.c b/src/box/sql.c
> index 580f3fa..116e3e8 100644
> --- a/src/box/sql.c
> +++ b/src/box/sql.c
> @@ -1362,13 +1362,8 @@ sql_checks_resolve_space_def_reference(ExprList *expr_list,
> 	parser.parse_only = true;
> 
> 	sql_resolve_self_reference(&parser, def, NC_IsCheck, NULL, expr_list);
> -	int rc = 0;
> -	if (parser.rc != SQL_OK) {
> -		/* Tarantool error may be already set with diag. */
> -		if (parser.rc != SQL_TARANTOOL_ERROR)
> -			diag_set(ClientError, ER_SQL, parser.zErrMsg);
> -		rc = -1;
> -	}
> +	if (parser.rc != SQL_OK)
> +		return -1;

Since now we have only one possible RC, lets remove
its name and simply check (parser.rc != 0).
Or, as suggested Konstantin, better replace rc with bool is_aborted flag.

> 	sql_parser_destroy(&parser);
> -	return rc;
> +	return 0;
> }
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index deb5b89..6afca4a 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -493,16 +493,10 @@ sql_column_add_nullable_action(struct Parse *parser,
> 	struct field_def *field = &def->fields[def->field_count - 1];
> 	if (field->nullable_action != ON_CONFLICT_ACTION_DEFAULT &&
> 	    nullable_action != field->nullable_action) {
> -		/* Prevent defining nullable_action many times. */
> -		const char *err_msg =
> -			tt_sprintf("NULL declaration for column '%s' of table "
> -				   "'%s' has been already set to '%s'",
> -				   field->name, def->name,
> -				   on_conflict_action_strs[field->
> -							   nullable_action]);
> -		diag_set(ClientError, ER_SQL, err_msg);
> -		parser->rc = SQL_TARANTOOL_ERROR;
> -		parser->nErr++;
> +		sqlErrorMsg(parser, "NULL declaration for column '%s' of "\
> +			    "table '%s' has been already set to '%s'",
> +			    field->name, def->name,
> +			    on_conflict_action_strs[field-> nullable_action]);

This looks like step back in our attempt at using diag_set.
We do you need to incapsulate diag into sqlErrorMsg?

> 		return;
> 	}
> 	field->nullable_action = nullable_action;
> diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
> index 5170c7f..a7bf3b3 100644
> --- a/src/box/sql/delete.c
> +++ b/src/box/sql/delete.c
> @@ -94,31 +94,22 @@ sql_table_truncate(struct Parse *parse, struct SrcList *tab_list)
> 	struct space *space = space_by_name(tab_name);
> 	if (space == NULL) {
> 		diag_set(ClientError, ER_NO_SUCH_SPACE, tab_name);
> -		goto tarantool_error;
> +		sql_parser_error(parse);

Look, anyway you remove this function in next commit.
Next time please consider order of refactoring.

> 	}
> 	if (! rlist_empty(&space->parent_fk_constraint)) {
> -		const char *err_msg =
> -			tt_sprintf("can not truncate space '%s' because other "
> -				   "objects depend on it", space->def->name);
> -		diag_set(ClientError, ER_SQL, err_msg);
> -		goto tarantool_error;
> +		sqlErrorMsg(parse, "can not truncate space '%s' because other "
> +			    "objects depend on it", space->def->name);

Replace invocation of sqlErrorMsg with diag_set + parser->rc.
The same in other places.

> @@ -146,11 +145,7 @@ sqlPrepare(sql * db,	/* Database handle. */
> 		*ppStmt = (sql_stmt *) sParse.pVdbe;
> 	}
> 
> -	if (zErrMsg) {
> -		sqlErrorWithMsg(db, rc, "%s", zErrMsg);
> -	} else {
> -		sqlError(db, rc);
> -	}
> +	sqlError(db, rc);

sqlError seems to be useless/dead. Please, make a note somewhere
to remove it as follow-up to error-refactoring patch-set.

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

* [tarantool-patches] Re: [PATCH v2 5/5] sql: remove field nErr of struct Parse
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 5/5] sql: remove field nErr " imeevma
  2019-02-26  8:27   ` [tarantool-patches] " Konstantin Osipov
@ 2019-02-26 14:48   ` n.pettik
  1 sibling, 0 replies; 21+ messages in thread
From: n.pettik @ 2019-02-26 14:48 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen


> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index 6afca4a..6621af4 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -92,7 +92,6 @@ save_record(struct Parse *parser, uint32_t space_id, int reg_key,
> 		diag_set(OutOfMemory, sizeof(*record), "region_alloc",
> 			 "record");
> 		parser->rc = SQL_TARANTOOL_ERROR;
> -		parser->nErr++;
> 		return;
> 	}
> 	record->space_id = space_id;
> @@ -145,9 +144,11 @@ sql_finish_coding(struct Parse *parse_context)
> 			     "Exit with an error if CREATE statement fails"));
> 	}
> 
> -	if (db->mallocFailed || parse_context->nErr != 0) {
> -		if (parse_context->rc == SQL_OK)
> -			parse_context->rc = SQL_ERROR;
> +	if (parse_context->rc == SQL_TARANTOOL_ERROR)

rc == 0 / ! abort

> +		return;
> +	if (db->mallocFailed) {
> +		diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Out of memory”);

Why generic when it is OOM error?

> +		parse_context->rc = SQL_TARANTOOL_ERROR;

rc = -1 / abort = true

> 		return;
> 	}
> 	/*
> @@ -189,13 +190,13 @@ sql_finish_coding(struct Parse *parse_context)
> 		sqlVdbeGoto(v, 1);
> 	}
> 	/* Get the VDBE program ready for execution. */
> -	if (parse_context->nErr == 0 && !db->mallocFailed) {
> +	if (parse_context->rc != SQL_TARANTOOL_ERROR && !db->mallocFailed) {
> 		assert(parse_context->iCacheLevel == 0);
> 		sqlVdbeMakeReady(v, parse_context);
> 		parse_context->rc = SQL_DONE;
> -	} else {
> -		if (parse_context->rc != SQL_TARANTOOL_ERROR)
> -			parse_context->rc = SQL_ERROR;
> +	} else if (parse_context->rc != SQL_TARANTOOL_ERROR) {
> +		diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Out of memory");
> +		parse_context->rc = SQL_TARANTOOL_ERROR;

The same is here and in other places .

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

* [tarantool-patches] Re: [PATCH v2 3/5] sql: save SQL parser errors in diag_set()
  2019-02-25 23:01   ` [tarantool-patches] " n.pettik
  2019-02-26  8:25     ` Konstantin Osipov
@ 2019-02-26 15:29     ` Imeev Mergen
  1 sibling, 0 replies; 21+ messages in thread
From: Imeev Mergen @ 2019-02-26 15:29 UTC (permalink / raw)
  To: n.pettik, tarantool-patches

Hi! Thank you for review! My answers below

On 2/26/19 2:01 AM, n.pettik wrote:
>
>> On 25 Feb 2019, at 20:14, imeevma@tarantool.org wrote:
>>
>> After this patch all SQL parser errors will be saved in diag_set()
>> instead of field zErrMsg of struct Parse.
>>
>> Part of #3965
>> ---
>> src/box/errcode.h           | 1 +
>> src/box/sql/build.c         | 3 ++-
>> src/box/sql/util.c          | 6 +++---
>> test/box/misc.result        | 1 +
>> test/sql-tap/check.test.lua | 2 +-
>> test/sql/triggers.result    | 4 ++--
>> 6 files changed, 10 insertions(+), 7 deletions(-)
>>
>> diff --git a/src/box/errcode.h b/src/box/errcode.h
>> index 6546b2f..779d927 100644
>> --- a/src/box/errcode.h
>> +++ b/src/box/errcode.h
>> @@ -238,6 +238,7 @@ struct errcode_record {
>> 	/*183 */_(ER_SQL_KEYWORD_IS_RESERVED,	"Keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
>> 	/*184 */_(ER_SQL_SYNTAX_NEAR,		"Unrecognized syntax near '%.*s'") \
>> 	/*185 */_(ER_SQL_UNKNOWN_TOKEN,		"Syntax error: unrecognized token: '%.*s'") \
>> +	/*186 */_(ER_SQL_PARSER_GENERIC,	"%s") \
> Hmm, what is this?
All unprocessed SQL errors will be inserted into the diag under
this error code.

>
>> /*
>>   * !IMPORTANT! Please follow instructions at start of the file
>> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
>> index f112c9f..deb5b89 100644
>> --- a/src/box/sql/build.c
>> +++ b/src/box/sql/build.c
>> @@ -194,7 +194,8 @@ sql_finish_coding(struct Parse *parse_context)
>> 		sqlVdbeMakeReady(v, parse_context);
>> 		parse_context->rc = SQL_DONE;
>> 	} else {
>> -		parse_context->rc = SQL_ERROR;
>> +		if (parse_context->rc != SQL_TARANTOOL_ERROR)
>> +			parse_context->rc = SQL_ERROR;
> What a mess, explain this please.
Before this change it was possible to replace SQL_TARANTOOL_ERROR
by SQL_ERROR in parse_context->rc. It actually happened in one
test.

>
>> 	}
>> }
>> /**
>> diff --git a/src/box/sql/util.c b/src/box/sql/util.c
>> index c89e2e8..e4c93cb 100644
>> --- a/src/box/sql/util.c
>> +++ b/src/box/sql/util.c
>> @@ -236,10 +236,10 @@ sqlErrorMsg(Parse * pParse, const char *zFormat, ...)
>> 	va_start(ap, zFormat);
>> 	zMsg = sqlVMPrintf(db, zFormat, ap);
>> 	va_end(ap);
>> +	diag_set(ClientError, ER_SQL_PARSER_GENERIC, zMsg);
>> +	sqlDbFree(db, zMsg);
>> 	pParse->nErr++;
>> -	sqlDbFree(db, pParse->zErrMsg);
>> -	pParse->zErrMsg = zMsg;
>> -	pParse->rc = SQL_ERROR;
>> +	pParse->rc = SQL_TARANTOOL_ERROR;
>> }
> Ok, so you decided to push all errors in one heap.
> That’s definitely not what we discussed earlier.
> Konstantin asked you to move each independent error
> in a separate error code (and I agree with him to a lesser
> or greater extent). Well, at least group them to semantic/
> syntax groups. And instead you simply do this.
> Then, I don’t understand purpose of all previous patches.
>
> Am I missing something?
This will allow us to quickly fix issue 3505. These errors will be
processed later.

>

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

* [tarantool-patches] Re: [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse
  2019-02-26 14:47   ` [tarantool-patches] " n.pettik
@ 2019-02-26 15:36     ` Imeev Mergen
  2019-02-26 18:17       ` n.pettik
  0 siblings, 1 reply; 21+ messages in thread
From: Imeev Mergen @ 2019-02-26 15:36 UTC (permalink / raw)
  To: n.pettik, tarantool-patches

Hi! Thank you for review! My answers below.

On 2/26/19 5:47 PM, n.pettik wrote:
>> diff --git a/src/box/sql.c b/src/box/sql.c
>> index 580f3fa..116e3e8 100644
>> --- a/src/box/sql.c
>> +++ b/src/box/sql.c
>> @@ -1362,13 +1362,8 @@ sql_checks_resolve_space_def_reference(ExprList *expr_list,
>> 	parser.parse_only = true;
>>
>> 	sql_resolve_self_reference(&parser, def, NC_IsCheck, NULL, expr_list);
>> -	int rc = 0;
>> -	if (parser.rc != SQL_OK) {
>> -		/* Tarantool error may be already set with diag. */
>> -		if (parser.rc != SQL_TARANTOOL_ERROR)
>> -			diag_set(ClientError, ER_SQL, parser.zErrMsg);
>> -		rc = -1;
>> -	}
>> +	if (parser.rc != SQL_OK)
>> +		return -1;
> Since now we have only one possible RC, lets remove
> its name and simply check (parser.rc != 0).
> Or, as suggested Konstantin, better replace rc with bool is_aborted flag.
Do you mind if I do this in a new patch?
>
>> 	sql_parser_destroy(&parser);
>> -	return rc;
>> +	return 0;
>> }
>> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
>> index deb5b89..6afca4a 100644
>> --- a/src/box/sql/build.c
>> +++ b/src/box/sql/build.c
>> @@ -493,16 +493,10 @@ sql_column_add_nullable_action(struct Parse *parser,
>> 	struct field_def *field = &def->fields[def->field_count - 1];
>> 	if (field->nullable_action != ON_CONFLICT_ACTION_DEFAULT &&
>> 	    nullable_action != field->nullable_action) {
>> -		/* Prevent defining nullable_action many times. */
>> -		const char *err_msg =
>> -			tt_sprintf("NULL declaration for column '%s' of table "
>> -				   "'%s' has been already set to '%s'",
>> -				   field->name, def->name,
>> -				   on_conflict_action_strs[field->
>> -							   nullable_action]);
>> -		diag_set(ClientError, ER_SQL, err_msg);
>> -		parser->rc = SQL_TARANTOOL_ERROR;
>> -		parser->nErr++;
>> +		sqlErrorMsg(parser, "NULL declaration for column '%s' of "\
>> +			    "table '%s' has been already set to '%s'",
>> +			    field->name, def->name,
>> +			    on_conflict_action_strs[field-> nullable_action]);
> This looks like step back in our attempt at using diag_set.
> We do you need to incapsulate diag into sqlErrorMsg?
I thought that it was good idea to incapsulate all SQL errors that
cannot be fixed in just parse_context->rc = SQL_TARANTOOL_ERROR
and diag_set(). Here it uses tt_printf() in addition to these two
commands.

>
>> 		return;
>> 	}
>> 	field->nullable_action = nullable_action;
>> diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
>> index 5170c7f..a7bf3b3 100644
>> --- a/src/box/sql/delete.c
>> +++ b/src/box/sql/delete.c
>> @@ -94,31 +94,22 @@ sql_table_truncate(struct Parse *parse, struct SrcList *tab_list)
>> 	struct space *space = space_by_name(tab_name);
>> 	if (space == NULL) {
>> 		diag_set(ClientError, ER_NO_SUCH_SPACE, tab_name);
>> -		goto tarantool_error;
>> +		sql_parser_error(parse);
> Look, anyway you remove this function in next commit.
> Next time please consider order of refactoring.
You are right, I will return to what was before and refactor in
the next commit.
>
>> 	}
>> 	if (! rlist_empty(&space->parent_fk_constraint)) {
>> -		const char *err_msg =
>> -			tt_sprintf("can not truncate space '%s' because other "
>> -				   "objects depend on it", space->def->name);
>> -		diag_set(ClientError, ER_SQL, err_msg);
>> -		goto tarantool_error;
>> +		sqlErrorMsg(parse, "can not truncate space '%s' because other "
>> +			    "objects depend on it", space->def->name);
> Replace invocation of sqlErrorMsg with diag_set + parser->rc.
> The same in other places.
Answer is the same as in second question.
>
>> @@ -146,11 +145,7 @@ sqlPrepare(sql * db,	/* Database handle. */
>> 		*ppStmt = (sql_stmt *) sParse.pVdbe;
>> 	}
>>
>> -	if (zErrMsg) {
>> -		sqlErrorWithMsg(db, rc, "%s", zErrMsg);
>> -	} else {
>> -		sqlError(db, rc);
>> -	}
>> +	sqlError(db, rc);
> sqlError seems to be useless/dead. Please, make a note somewhere
> to remove it as follow-up to error-refactoring patch-set.
Do you mind if I do this in a new patch?
>
>

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

* [tarantool-patches] Re: [PATCH v2 2/5] sql: rework syntax errors
  2019-02-26  8:24     ` Konstantin Osipov
  2019-02-26 12:59       ` n.pettik
@ 2019-02-26 15:59       ` Imeev Mergen
  1 sibling, 0 replies; 21+ messages in thread
From: Imeev Mergen @ 2019-02-26 15:59 UTC (permalink / raw)
  To: Konstantin Osipov, tarantool-patches

Hi! Thank you for review. My answer below

On 2/26/19 11:24 AM, Konstantin Osipov wrote:
> * n.pettik <korablev@tarantool.org> [19/02/25 23:05]:
>> Quite strange name for err code.
>> I’d rather say ER_SQL_UNRECOGNIZED_SYMBOL/SYNTAX.
>> Is this message suggested by Konstantin? To be honest, I would
>> prefer old one. “Unrecognized syntax” doesn’t sound good and clear enough,
>> at least for me. Personally I would say “Syntax error near %s”.
>> The last one is used in several DBs, so I suppose it is common way to raise
>> errors like that.
> Yes, the name is suggested by me. There is a name clash with a
> generic ER_SYNTAX_ERROR. I also requested to add line/character
> numbers to the error message, which I don't see in the patch.
>
> Mergen, did you find that this is not possible to do?
As far as I understand, this is not yet possible. All '\ n' are
currently treated as spaces. To change this, we need to define a
new character class in tokenize.c and make all related changes to
the parser. I do not think that this should be done in issue 3965.
May I mention this later as a follow-up of the issue?
>
>

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

* [tarantool-patches] Re: [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse
  2019-02-26 15:36     ` Imeev Mergen
@ 2019-02-26 18:17       ` n.pettik
  0 siblings, 0 replies; 21+ messages in thread
From: n.pettik @ 2019-02-26 18:17 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Imeev Mergen

[-- Attachment #1: Type: text/plain, Size: 4500 bytes --]


> On 26 Feb 2019, at 18:36, Imeev Mergen <imeevma@tarantool.org> wrote:
> Hi! Thank you for review! My answers below.
> On 2/26/19 5:47 PM, n.pettik wrote:
>>> diff --git a/src/box/sql.c b/src/box/sql.c
>>> index 580f3fa..116e3e8 100644
>>> --- a/src/box/sql.c
>>> +++ b/src/box/sql.c
>>> @@ -1362,13 +1362,8 @@ sql_checks_resolve_space_def_reference(ExprList *expr_list,
>>> 	parser.parse_only = true;
>>> 
>>> 	sql_resolve_self_reference(&parser, def, NC_IsCheck, NULL, expr_list);
>>> -	int rc = 0;
>>> -	if (parser.rc != SQL_OK) {
>>> -		/* Tarantool error may be already set with diag. */
>>> -		if (parser.rc != SQL_TARANTOOL_ERROR)
>>> -			diag_set(ClientError, ER_SQL, parser.zErrMsg);
>>> -		rc = -1;
>>> -	}
>>> +	if (parser.rc != SQL_OK)
>>> +		return -1;
>> Since now we have only one possible RC, lets remove
>> its name and simply check (parser.rc != 0).
>> Or, as suggested Konstantin, better replace rc with bool is_aborted flag.
> Do you mind if I do this in a new patch?

Sure, but place it before this one.

>>> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
>>> index deb5b89..6afca4a 100644
>>> --- a/src/box/sql/build.c
>>> +++ b/src/box/sql/build.c
>>> @@ -493,16 +493,10 @@ sql_column_add_nullable_action(struct Parse *parser,
>>> 	struct field_def *field = &def->fields[def->field_count - 1];
>>> 	if (field->nullable_action != ON_CONFLICT_ACTION_DEFAULT &&
>>> 	    nullable_action != field->nullable_action) {
>>> -		/* Prevent defining nullable_action many times. */
>>> -		const char *err_msg =
>>> -			tt_sprintf("NULL declaration for column '%s' of table "
>>> -				   "'%s' has been already set to '%s'",
>>> -				   field->name, def->name,
>>> -				   on_conflict_action_strs[field->
>>> -							   nullable_action]);
>>> -		diag_set(ClientError, ER_SQL, err_msg);
>>> -		parser->rc = SQL_TARANTOOL_ERROR;
>>> -		parser->nErr++;
>>> +		sqlErrorMsg(parser, "NULL declaration for column '%s' of "\
>>> +			    "table '%s' has been already set to '%s'",
>>> +			    field->name, def->name,
>>> +			    on_conflict_action_strs[field-> nullable_action]);
>> This looks like step back in our attempt at using diag_set.
>> We do you need to incapsulate diag into sqlErrorMsg?
> I thought that it was good idea to incapsulate all SQL errors that

No, it wasn’t.

> cannot be fixed in just parse_context->rc = SQL_TARANTOOL_ERROR
> and diag_set(). Here it uses tt_printf() in addition to these two
> commands.

It’s OK. Revert this (and other) change(s), please. Lets use pure
diag_set + abort flag.

>>> 		return;
>>> 	}
>>> 	field->nullable_action = nullable_action;
>>> diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
>>> index 5170c7f..a7bf3b3 100644
>>> --- a/src/box/sql/delete.c
>>> +++ b/src/box/sql/delete.c
>>> @@ -94,31 +94,22 @@ sql_table_truncate(struct Parse *parse, struct SrcList *tab_list)
>>> 	struct space *space = space_by_name(tab_name);
>>> 	if (space == NULL) {
>>> 		diag_set(ClientError, ER_NO_SUCH_SPACE, tab_name);
>>> -		goto tarantool_error;
>>> +		sql_parser_error(parse);
>> Look, anyway you remove this function in next commit.
>> Next time please consider order of refactoring.
> You are right, I will return to what was before and refactor in
> the next commit.

Don’t waste time now, it was just advice to keep in mind.

>>> 	}
>>> 	if (! rlist_empty(&space->parent_fk_constraint)) {
>>> -		const char *err_msg =
>>> -			tt_sprintf("can not truncate space '%s' because other "
>>> -				   "objects depend on it", space->def->name);
>>> -		diag_set(ClientError, ER_SQL, err_msg);
>>> -		goto tarantool_error;
>>> +		sqlErrorMsg(parse, "can not truncate space '%s' because other "
>>> +			    "objects depend on it", space->def->name);
>> Replace invocation of sqlErrorMsg with diag_set + parser->rc.
>> The same in other places.
> Answer is the same as in second question.
>> 
>>> @@ -146,11 +145,7 @@ sqlPrepare(sql * db,	/* Database handle. */
>>> 		*ppStmt = (sql_stmt *) sParse.pVdbe;
>>> 	}
>>> 
>>> -	if (zErrMsg) {
>>> -		sqlErrorWithMsg(db, rc, "%s", zErrMsg);
>>> -	} else {
>>> -		sqlError(db, rc);
>>> -	}
>>> +	sqlError(db, rc);
>> sqlError seems to be useless/dead. Please, make a note somewhere
>> to remove it as follow-up to error-refactoring patch-set.
> Do you mind if I do this in a new patch?

You don’t have to do it right now, it can wait till 2.2
Just file this issue somewhere.


[-- Attachment #2: Type: text/html, Size: 23039 bytes --]

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

* [tarantool-patches] Re: [PATCH v2 1/5] sql: remove "syntax error after column name" error
  2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error imeevma
  2019-02-25 19:34   ` [tarantool-patches] " n.pettik
@ 2019-02-27 11:32   ` Kirill Yukhin
  1 sibling, 0 replies; 21+ messages in thread
From: Kirill Yukhin @ 2019-02-27 11:32 UTC (permalink / raw)
  To: tarantool-patches; +Cc: korablev

Hello,

On 25 Feb 20:14, imeevma@tarantool.org wrote:
> Error "syntax error after column name" does not make any sense.
> Let's remove it.
> 
> Part of #3965
> ---
>  src/box/sql/parse.y        | 22 +++++-----------------
>  test/sql-tap/view.test.lua |  2 +-
>  2 files changed, 6 insertions(+), 18 deletions(-)

I've checked this one into 2.1 branch.

--
Regards, Kirill Yukhin

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

end of thread, other threads:[~2019-02-27 11:32 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-25 17:14 [tarantool-patches] [PATCH v2 0/5] sql: use diag_set() for errors in SQL imeevma
2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 1/5] sql: remove "syntax error after column name" error imeevma
2019-02-25 19:34   ` [tarantool-patches] " n.pettik
2019-02-27 11:32   ` Kirill Yukhin
2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 2/5] sql: rework syntax errors imeevma
2019-02-25 20:02   ` [tarantool-patches] " n.pettik
2019-02-26  8:24     ` Konstantin Osipov
2019-02-26 12:59       ` n.pettik
2019-02-26 13:12         ` Konstantin Osipov
2019-02-26 15:59       ` Imeev Mergen
2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 3/5] sql: save SQL parser errors in diag_set() imeevma
2019-02-25 23:01   ` [tarantool-patches] " n.pettik
2019-02-26  8:25     ` Konstantin Osipov
2019-02-26 15:29     ` Imeev Mergen
2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 4/5] sql: remove file zErrMsg of struct Parse imeevma
2019-02-26 14:47   ` [tarantool-patches] " n.pettik
2019-02-26 15:36     ` Imeev Mergen
2019-02-26 18:17       ` n.pettik
2019-02-25 17:14 ` [tarantool-patches] [PATCH v2 5/5] sql: remove field nErr " imeevma
2019-02-26  8:27   ` [tarantool-patches] " Konstantin Osipov
2019-02-26 14:48   ` n.pettik

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