[Tarantool-patches] [tarantool-patches] [PATCH] sql: print line and column number in error message

Roman Khabibov roman.habibov at tarantool.org
Wed Oct 23 13:40:34 MSK 2019


Hi! Thanks for the review.

> On Oct 14, 2019, at 18:47, Nikita Pettik <korablev at tarantool.org> wrote:
> 
> On 07 Oct 00:05, Roman Khabibov wrote:
>> Count the number of rows and columns during query parsing. This is
>> to make it easier for the user to find errors in multiline
>> queries.
>> 
>> Closes #2611
>> 
>> # Please enter the commit message for your changes. Lines starting
> 
> ?
Oops.

>> ---
>> diff --git a/src/box/errcode.h b/src/box/errcode.h
>> index d5d396d87..36e5c179f 100644
>> --- a/src/box/errcode.h
>> +++ b/src/box/errcode.h
>> @@ -235,9 +235,9 @@ struct errcode_record {
>> 	/*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_UNRECOGNIZED_SYNTAX,	"Syntax error near '%.*s'") \
>> -	/*185 */_(ER_SQL_UNKNOWN_TOKEN,		"Syntax error: unrecognized token: '%.*s'") \
>> +	/*183 */_(ER_SQL_KEYWORD_IS_RESERVED,	"Keyword '%.*s' on line %d at character %d is reserved. Please use double quotes if '%.*s' is an identifier.") \
>> +	/*184 */_(ER_SQL_UNRECOGNIZED_SYNTAX,	"Syntax error on line %d at character %d near '%.*s'") \
>> +	/*185 */_(ER_SQL_UNKNOWN_TOKEN,		"Syntax error: on line %d at character %d unrecognized token: '%.*s'") \
>> 	/*186 */_(ER_SQL_PARSER_GENERIC,	"%s") \
> 
> What about other syntax related errors like ER_SQL_PARSER_GENERIC,
> ER_SQL_SYNTAX? Please use the same pattern for all errors:
> 
> "On line %d at/near position %d ..." OR
> "Syntax error on line %d at column %d: …”
Unfortunately, I can print line count and position only during the process
of tokenizing. Outside of the parse.y and tokenize.c we will just print the
last symbol position of a query, because this process is assumed to be
completed, as I understood.

diff --git a/src/box/errcode.h b/src/box/errcode.h
index d5d396d87..0e2a782a5 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -256,6 +256,11 @@ struct errcode_record {
 	/*201 */_(ER_NO_SUCH_FIELD_NAME,	"Field '%s' was not found in the tuple") \
 	/*202 */_(ER_FUNC_WRONG_ARG_COUNT,	"Wrong number of arguments is passed to %s(): expected %s, got %d") \
 	/*203 */_(ER_BOOTSTRAP_READONLY,	"Trying to bootstrap a local read-only instance as master") \
+	/*204 */_(ER_SQL_SYNTAX_WITH_POS,	"Syntax error on line %d at column %d in %s: %s") \
+	/*205 */_(ER_SQL_PARSER_GENERIC_WITH_POS,	"Syntax error on line %d at column %d: %s") \
+	/*206 */_(ER_SQL_KEYWORD_IS_RESERVED_WITH_POS,	"Syntax error on line %d at column %d: keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
+	/*207 */_(ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS,	"Syntax error on line %d at column %d near '%.*s'") \
+	/*208 */_(ER_SQL_UNKNOWN_TOKEN_WITH_POS,	"Syntax error on line %d at column %d unrecognized token: '%.*s'") \

>> 	/*187 */_(ER_SQL_ANALYZE_ARGUMENT,	"ANALYZE statement argument %s is not a base table") \
>> 	/*188 */_(ER_SQL_COLUMN_COUNT_MAX,	"Failed to create space '%s': space column count %d exceeds the limit (%d)") \
>> diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
>> index e077a8b5e..d23feba96 100644
>> --- a/src/box/sql/prepare.c
>> +++ b/src/box/sql/prepare.c
>> @@ -243,6 +243,8 @@ sql_parser_create(struct Parse *parser, struct sql *db, uint32_t sql_flags)
>> 	memset(parser, 0, sizeof(struct Parse));
>> 	parser->db = db;
>> 	parser->sql_flags = sql_flags;
>> +	parser->line_count = 1;
>> +	parser->offset_count = 1;
>> 	region_create(&parser->region, &cord()->slabc);
>> }
>> 
>> diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
>> index fbb39878a..89839e046 100644
>> --- a/src/box/sql/sqlInt.h
>> +++ b/src/box/sql/sqlInt.h
>> @@ -2172,6 +2172,8 @@ struct Parse {
>>   ***********************************************************************/
>> 
>> 	Token sLastToken;	/* The last token parsed */
>> +	int line_count;		/* The line counter. */
>> +	int offset_count;	/* The offset counter. */
> 
> Nit: use uint32_t type; use proper commenting style (/**...*/ above
> the subject of comment); offset_count -> offset_pos/line_pos
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 1b6d92cb1..2831dd6dd 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2172,6 +2172,10 @@ struct Parse {
   ***********************************************************************/
 
 	Token sLastToken;	/* The last token parsed */
+	/** The line counter. */
+	uint32_t line_count;
+	/** The position in a line. */
+	uint32_t line_pos;
 	ynVar nVar;		/* Number of '?' variables seen in the SQL so far */
 	u8 explain;		/* True if the EXPLAIN flag is found on the query */
 	int nHeight;		/* Expression tree height of current sub-select */

>> diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
>> index 9fa069d09..ee3978f3a 100644
>> --- a/src/box/sql/tokenize.c
>> +++ b/src/box/sql/tokenize.c
>> @@ -192,12 +193,20 @@ sql_token(const char *z, int *type, bool *is_reserved)
>> 		i = 1 + sql_skip_spaces(z+1);
>> 		*type = TK_SPACE;
>> 		return i;
>> +	case CC_LINEFEED:
>> +		*type = TK_LINEFEED;
>> +		return 1;
>> 	case CC_MINUS:
>> 		if (z[1] == '-') {
>> -			for (i = 2; (c = z[i]) != 0 && c != '\n'; i++) {
>> +			for (i = 2; true; i++) {
>> +				if (z[i] == '\0') {
>> +					*type = TK_SPACE;
> 
> Please add a comment explaining that here we are ignoring comment
> till the end of string and add test case.
@@ -192,12 +193,24 @@ sql_token(const char *z, int *type, bool *is_reserved)
 		i = 1 + sql_skip_spaces(z+1);
 		*type = TK_SPACE;
 		return i;
+	case CC_LINEFEED:
+		*type = TK_LINEFEED;
+		return 1;
 	case CC_MINUS:
+		/*
+		 * Ignore single-line comment started with "--"
+		 * till the end of parsing string or next line.
+		 */
 		if (z[1] == '-') {
-			for (i = 2; (c = z[i]) != 0 && c != '\n'; i++) {
+			for (i = 2; true; i++) {
+				if (z[i] == '\0') {
+					*type = TK_SPACE;
+					return i;
+				} else if (z[i] == '\n') {
+					*type = TK_LINEFEED;
+					return ++i;
+				}
 			}
-			*type = TK_SPACE;
-			return i;
 		}
 		*type = TK_MINUS;
 		return 1;

And the test.
diff --git a/test/sql-tap/tokenize.test.lua b/test/sql-tap/tokenize.test.lua
index b1a097e23..eb11eb8a4 100755
--- a/test/sql-tap/tokenize.test.lua
+++ b/test/sql-tap/tokenize.test.lua
+--
+--gh-2611 Check the correct parsing of single-line comments.
+--
+test:do_execsql_test(
+    "tokenize-3.1",
+    [[
+        SELECT 1 + -- 1 + 1.
+        1
+    ]], {
+        -- <tokenize-2.2>
+        2
+        -- </tokenize-2.2>
+    })
 
+test:do_catchsql_test(
+    "tokenize-3.2",
+    [[
+        SELECT 1 + -- Syntax error.
+        *
+    ]], {
+        -- <tokenize-2.2>
+        1,"Syntax error on line 2 at column 9 near '*'"
+        -- </tokenize-2.2>
+    })


>> diff --git a/test/sql-tap/alter2.test.lua b/test/sql-tap/alter2.test.lua
>> index e0bd60727..56030e1f8 100755
>> --- a/test/sql-tap/alter2.test.lua
>> +++ b/test/sql-tap/alter2.test.lua
>> diff --git a/test/sql-tap/keyword1.test.lua b/test/sql-tap/keyword1.test.lua
>> index 03b1054d2..b43e30876 100755
>> --- a/test/sql-tap/keyword1.test.lua
>> +++ b/test/sql-tap/keyword1.test.lua
>> @@ -238,12 +238,61 @@ end
>> 
>> for _, kw in ipairs(bannedkws) do
>>     query = 'CREATE TABLE '..kw..'(a INT PRIMARY KEY);'
>> -    test:do_catchsql_test(
>> +    if kw == 'end' then
>> +        test:do_catchsql_test(
>>         "bannedkw1-"..kw..".1",
>>         query, {
>> -            1, "Keyword '"..kw.."' is reserved. Please use double quotes if '"..kw.."' is an identifier."
>> +            1, "Keyword '"..kw.."' on line 1 at character 17 is reserved. Please use double quotes if '"..kw.."' is an identifier."
>>         })
> 
> Why not base_len + string.len(kw)? These if-else's look extremely awful.
diff --git a/test/sql-tap/keyword1.test.lua b/test/sql-tap/keyword1.test.lua
index 03b1054d2..ffb18c4fd 100755
--- a/test/sql-tap/keyword1.test.lua
+++ b/test/sql-tap/keyword1.test.lua
@@ -238,11 +238,25 @@ end
 
 for _, kw in ipairs(bannedkws) do
     query = 'CREATE TABLE '..kw..'(a INT PRIMARY KEY);'
-    test:do_catchsql_test(
+    if kw == 'end' or kw == 'match' or kw == 'release' or kw == 'rename' or
+       kw == 'replace' or kw == 'binary' or kw == 'character' or
+       kw == 'smallint' then
+        test:do_catchsql_test(
         "bannedkw1-"..kw..".1",
         query, {
-            1, "Keyword '"..kw.."' is reserved. Please use double quotes if '"..kw.."' is an identifier."
+            1, "Syntax error on line 1 at column "..14 + string.len(kw)..
+            ": keyword '"..kw.."' is reserved. Please use double quotes if '"
+            ..kw.."' is an identifier."
         })
+    else
+        test:do_catchsql_test(
+        "bannedkw1-"..kw..".1",
+        query, {
+            1, "Syntax error on line 1 at column 14: keyword '"..kw..
+            "' is reserved. Please use double quotes if '"..kw..
+            "' is an identifier."
+        })
+    end
 end

>> 
>> -
>> test:finish_test()
>> diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
>> index b84093e3c..cc61016ac 100755
>> --- a/test/sql-tap/misc1.test.lua
>> +++ b/test/sql-tap/misc1.test.lua
>> @@ -1,6 +1,6 @@
>> #!/usr/bin/env tarantool
>> test = require("sqltester")
>> -test:plan(58)
>> +test:plan(59)
>> 
>> --!./tcltestrunner.lua
>> -- 2001 September 15.
>> @@ -262,17 +262,26 @@ test:do_execsql_test(
>> -- before executing a command.  Thus if "WHERE" is misspelled on an UPDATE,
>> -- the user won't accidently update every record.
>> --
>> -test:do_catchsql_test(
>> -    "misc1-5.1",
>> +
>> +test:do_execsql_test(
>> +    "misc1-5.1.1",
>>     [[
>>         CREATE TABLE t3(a  INT primary key,b INT );
>>         INSERT INTO t3 VALUES(1,2);
>>         INSERT INTO t3 VALUES(3,4);
>> +    ]], {
>> +        -- <misc1-5.1.1>
>> +        -- </misc1-5.1.1>
> 
> Originally, these comments were generated automatically by tcl to Lua
> converter. You don't have to put them to each test's result :)
> 
>> +    })
>> +
>> +    1, "Syntax error on line 1 at character 60 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, "Syntax error near '='"
>> +    1, "Syntax error on line 1 at character 71 near '='"
>>     -- </6.9>
>> })
>> 
>> diff --git a/test/sql/checks.result b/test/sql/checks.result
>> index 50347bc3a..4ecab9ad4 100644
>> --- a/test/sql/checks.result
>> +++ b/test/sql/checks.result
>> @@ -39,8 +39,8 @@ _ = box.space.test:create_index('pk')
>> -- Invalid expression test.
>> box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5'})
>> ---
>> -- error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error near
>> -    ''<'''
>> +- error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error on
>> +    line 1 at character 10 near ''<'''
> 
> There's parse_only flag in struct Parse. You can use it to calculate
> correct position in expression.

diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index ed59a875a..7546271d8 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -33,10 +33,21 @@
   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) {
-    diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, TOKEN.n, TOKEN.z,
-             TOKEN.n, TOKEN.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED_WITH_POS,
+               pParse->line_count, pParse->line_pos, TOKEN.n, TOKEN.z, TOKEN.n,
+               TOKEN.z);
+    } else {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, TOKEN.n, TOKEN.z,
+               TOKEN.n, TOKEN.z);
+    }
   } else {
-    diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, TOKEN.n, TOKEN.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS, pParse->line_count,
+               pParse->line_pos, TOKEN.n, TOKEN.z);
+    } else {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, TOKEN.n, TOKEN.z);
+    }
   }
   pParse->is_aborted = true;
 }
@@ -274,7 +285,12 @@ columnname(A) ::= nm(A) typedef(Y). {sqlAddColumn(pParse,&A,&Y);}
 %type nm {Token}
 nm(A) ::= id(A). {
   if(A.isReserved) {
-    diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, A.n, A.z, A.n, A.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED_WITH_POS,
+               pParse->line_count, pParse->line_pos, A.n, A.z, A.n, A.z);
+    } else {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED,  A.n, A.z, A.n, A.z);
+    }
     pParse->is_aborted = true;
   }
 }
@@ -1072,15 +1088,25 @@ expr(A) ::= VARIABLE(X).     {
   Token t = X;
   if (pParse->parse_only) {
     spanSet(&A, &t, &t);
-    diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-             "bindings are not allowed in DDL");
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_PARSER_GENERIC_WITH_POS, pParse->line_count,
+               pParse->line_pos, "bindings are not allowed in DDL");
+    } else {
+      diag_set(ClientError, ER_SQL_PARSER_GENERIC,
+               "bindings are not allowed in DDL");
+    }
     pParse->is_aborted = true;
     A.pExpr = NULL;
   } 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) {
-      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+      if (!pParse->parse_only) {
+        diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS, pParse->line_count,
+                 pParse->line_pos, t.n, t.z);
+      } else {
+        diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+      }
       pParse->is_aborted = true;
     } else {
       sqlExprAssignVarNumber(pParse, A.pExpr, n);
@@ -1088,7 +1114,12 @@ expr(A) ::= VARIABLE(X).     {
   }else{
     assert( t.n>=2 );
     spanSet(&A, &t, &t);
-    diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS, pParse->line_count,
+               pParse->line_pos, t.n, t.z);
+    } else {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+    }
     pParse->is_aborted = true;
     A.pExpr = NULL;
   }
@@ -1604,8 +1635,9 @@ trigger_event(A) ::= UPDATE(X).          {A.a = @X; /*A-overwrites-X*/ A.b = 0;}
 trigger_event(A) ::= UPDATE OF idlist(X).{A.a = TK_UPDATE; A.b = X;}
 
 foreach_clause ::= . {
-  diag_set(ClientError, ER_SQL_PARSER_GENERIC, "FOR EACH STATEMENT "
-	       "triggers are not implemented, please supply FOR EACH ROW clause");
+  diag_set(ClientError, ER_SQL_PARSER_GENERIC_WITH_POS, pParse->line_count,
+           pParse->line_pos, "FOR EACH STATEMENT triggers are not implemented, "
+           "please supply FOR EACH ROW clause");
   pParse->is_aborted = true;
 }
 foreach_clause ::= FOR EACH ROW.
@@ -1635,8 +1667,9 @@ trigger_cmd_list(A) ::= trigger_cmd(A) SEMI. {
 trnm(A) ::= nm(A).
 trnm(A) ::= nm DOT nm(X). {
   A = X;
-  diag_set(ClientError, ER_SQL_PARSER_GENERIC, "qualified table names are not "\
-           "allowed on INSERT, UPDATE, and DELETE statements within triggers");
+  diag_set(ClientError, ER_SQL_PARSER_GENERIC_WITH_POS, pParse->line_count,
+           pParse->line_pos, "qualified table names are not allowed on INSERT, "
+           "UPDATE, and DELETE statements within triggers");
   pParse->is_aborted = true;
 }
 
@@ -1646,14 +1679,15 @@ trnm(A) ::= nm DOT nm(X). {
 //
 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");
+  diag_set(ClientError, ER_SQL_SYNTAX_WITH_POS, pParse->line_count,
+           pParse->line_pos, "trigger body", "the INDEXED BY clause is not "
+           "allowed on UPDATE or DELETE statements within triggers");
   pParse->is_aborted = true;
 }
 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");
+  diag_set(ClientError, ER_SQL_SYNTAX_WITH_POS, pParse->line_count,
+           pParse->line_pos, "trigger body", "the NOT INDEXED clause is not "
+           "allowed on UPDATE or DELETE statements within triggers");
   pParse->is_aborted = true;
 }

And the tests for these cases.
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 50347bc3a..4ef888c6a 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -42,6 +42,16 @@ box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5'})
 - error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error near
     ''<'''
 ...
+box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', '1.0E+'})
+---
+- error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error: unrecognized
+    token: ''1.0E'''
+...
+box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'CREATE'})
+---
+- error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Keyword ''CREATE''
+    is reserved. Please use double quotes if ''CREATE'' is an identifier.'
+...
 -- Non-existent space test.
 box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'})
 ---
@@ -160,7 +170,7 @@ box.execute("DROP TABLE t1")
 box.execute("CREATE TABLE first (id NUMBER PRIMARY KEY CHECK(id < 5), a INT CONSTRAINT ONE CHECK(a >< 5));")
 ---
 - null
-- Syntax error near '<'
+- Syntax error on line 1 at column 88 near '<'
 ...
 box.space.FIRST == nil
 ---


commit 747775f4c8ea531ee79e7befc311aa9c69411245
Author: Roman Khabibov <roman.habibov at tarantool.org>
Date:   Sat Sep 28 20:16:45 2019 +0300

    sql: print line and column number in error message
    
    Count the number of rows and columns during query parsing. This is
    to make it easier for the user to find errors in multiline
    queries.
    
    Closes #2611

diff --git a/extra/addopcodes.sh b/extra/addopcodes.sh
index c25f1e48e..cb6c84725 100755
--- a/extra/addopcodes.sh
+++ b/extra/addopcodes.sh
@@ -50,6 +50,7 @@ extras="            \
     ASTERISK        \
     SPAN            \
     ANALYZE         \
+    LINEFEED        \
     SPACE           \
     ILLEGAL         \
 "
diff --git a/src/box/errcode.h b/src/box/errcode.h
index d5d396d87..0e2a782a5 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -256,6 +256,11 @@ struct errcode_record {
 	/*201 */_(ER_NO_SUCH_FIELD_NAME,	"Field '%s' was not found in the tuple") \
 	/*202 */_(ER_FUNC_WRONG_ARG_COUNT,	"Wrong number of arguments is passed to %s(): expected %s, got %d") \
 	/*203 */_(ER_BOOTSTRAP_READONLY,	"Trying to bootstrap a local read-only instance as master") \
+	/*204 */_(ER_SQL_SYNTAX_WITH_POS,	"Syntax error on line %d at column %d in %s: %s") \
+	/*205 */_(ER_SQL_PARSER_GENERIC_WITH_POS,	"Syntax error on line %d at column %d: %s") \
+	/*206 */_(ER_SQL_KEYWORD_IS_RESERVED_WITH_POS,	"Syntax error on line %d at column %d: keyword '%.*s' is reserved. Please use double quotes if '%.*s' is an identifier.") \
+	/*207 */_(ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS,	"Syntax error on line %d at column %d near '%.*s'") \
+	/*208 */_(ER_SQL_UNKNOWN_TOKEN_WITH_POS,	"Syntax error on line %d at column %d unrecognized token: '%.*s'") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index ed59a875a..7546271d8 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -33,10 +33,21 @@
   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) {
-    diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, TOKEN.n, TOKEN.z,
-             TOKEN.n, TOKEN.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED_WITH_POS,
+               pParse->line_count, pParse->line_pos, TOKEN.n, TOKEN.z, TOKEN.n,
+               TOKEN.z);
+    } else {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, TOKEN.n, TOKEN.z,
+               TOKEN.n, TOKEN.z);
+    }
   } else {
-    diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, TOKEN.n, TOKEN.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS, pParse->line_count,
+               pParse->line_pos, TOKEN.n, TOKEN.z);
+    } else {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, TOKEN.n, TOKEN.z);
+    }
   }
   pParse->is_aborted = true;
 }
@@ -274,7 +285,12 @@ columnname(A) ::= nm(A) typedef(Y). {sqlAddColumn(pParse,&A,&Y);}
 %type nm {Token}
 nm(A) ::= id(A). {
   if(A.isReserved) {
-    diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED, A.n, A.z, A.n, A.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED_WITH_POS,
+               pParse->line_count, pParse->line_pos, A.n, A.z, A.n, A.z);
+    } else {
+      diag_set(ClientError, ER_SQL_KEYWORD_IS_RESERVED,  A.n, A.z, A.n, A.z);
+    }
     pParse->is_aborted = true;
   }
 }
@@ -1072,15 +1088,25 @@ expr(A) ::= VARIABLE(X).     {
   Token t = X;
   if (pParse->parse_only) {
     spanSet(&A, &t, &t);
-    diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-             "bindings are not allowed in DDL");
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_PARSER_GENERIC_WITH_POS, pParse->line_count,
+               pParse->line_pos, "bindings are not allowed in DDL");
+    } else {
+      diag_set(ClientError, ER_SQL_PARSER_GENERIC,
+               "bindings are not allowed in DDL");
+    }
     pParse->is_aborted = true;
     A.pExpr = NULL;
   } 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) {
-      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+      if (!pParse->parse_only) {
+        diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS, pParse->line_count,
+                 pParse->line_pos, t.n, t.z);
+      } else {
+        diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+      }
       pParse->is_aborted = true;
     } else {
       sqlExprAssignVarNumber(pParse, A.pExpr, n);
@@ -1088,7 +1114,12 @@ expr(A) ::= VARIABLE(X).     {
   }else{
     assert( t.n>=2 );
     spanSet(&A, &t, &t);
-    diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+    if (!pParse->parse_only) {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX_WITH_POS, pParse->line_count,
+               pParse->line_pos, t.n, t.z);
+    } else {
+      diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX, t.n, t.z);
+    }
     pParse->is_aborted = true;
     A.pExpr = NULL;
   }
@@ -1604,8 +1635,9 @@ trigger_event(A) ::= UPDATE(X).          {A.a = @X; /*A-overwrites-X*/ A.b = 0;}
 trigger_event(A) ::= UPDATE OF idlist(X).{A.a = TK_UPDATE; A.b = X;}
 
 foreach_clause ::= . {
-  diag_set(ClientError, ER_SQL_PARSER_GENERIC, "FOR EACH STATEMENT "
-	       "triggers are not implemented, please supply FOR EACH ROW clause");
+  diag_set(ClientError, ER_SQL_PARSER_GENERIC_WITH_POS, pParse->line_count,
+           pParse->line_pos, "FOR EACH STATEMENT triggers are not implemented, "
+           "please supply FOR EACH ROW clause");
   pParse->is_aborted = true;
 }
 foreach_clause ::= FOR EACH ROW.
@@ -1635,8 +1667,9 @@ trigger_cmd_list(A) ::= trigger_cmd(A) SEMI. {
 trnm(A) ::= nm(A).
 trnm(A) ::= nm DOT nm(X). {
   A = X;
-  diag_set(ClientError, ER_SQL_PARSER_GENERIC, "qualified table names are not "\
-           "allowed on INSERT, UPDATE, and DELETE statements within triggers");
+  diag_set(ClientError, ER_SQL_PARSER_GENERIC_WITH_POS, pParse->line_count,
+           pParse->line_pos, "qualified table names are not allowed on INSERT, "
+           "UPDATE, and DELETE statements within triggers");
   pParse->is_aborted = true;
 }
 
@@ -1646,14 +1679,15 @@ trnm(A) ::= nm DOT nm(X). {
 //
 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");
+  diag_set(ClientError, ER_SQL_SYNTAX_WITH_POS, pParse->line_count,
+           pParse->line_pos, "trigger body", "the INDEXED BY clause is not "
+           "allowed on UPDATE or DELETE statements within triggers");
   pParse->is_aborted = true;
 }
 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");
+  diag_set(ClientError, ER_SQL_SYNTAX_WITH_POS, pParse->line_count,
+           pParse->line_pos, "trigger body", "the NOT INDEXED clause is not "
+           "allowed on UPDATE or DELETE statements within triggers");
   pParse->is_aborted = true;
 }
 
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index e077a8b5e..6230a9cc0 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -243,6 +243,8 @@ sql_parser_create(struct Parse *parser, struct sql *db, uint32_t sql_flags)
 	memset(parser, 0, sizeof(struct Parse));
 	parser->db = db;
 	parser->sql_flags = sql_flags;
+	parser->line_count = 1;
+	parser->line_pos = 1;
 	region_create(&parser->region, &cord()->slabc);
 }
 
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 1b6d92cb1..2831dd6dd 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2172,6 +2172,10 @@ struct Parse {
   ***********************************************************************/
 
 	Token sLastToken;	/* The last token parsed */
+	/** The line counter. */
+	uint32_t line_count;
+	/** The position in a line. */
+	uint32_t line_pos;
 	ynVar nVar;		/* Number of '?' variables seen in the SQL so far */
 	u8 explain;		/* True if the EXPLAIN flag is found on the query */
 	int nHeight;		/* Expression tree height of current sub-select */
diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
index 9fa069d09..adf7f4072 100644
--- a/src/box/sql/tokenize.c
+++ b/src/box/sql/tokenize.c
@@ -82,10 +82,11 @@
 #define CC_TILDA     25		/* '~' */
 #define CC_DOT       26		/* '.' */
 #define CC_ILLEGAL   27		/* Illegal character */
+#define CC_LINEFEED  28		/* '\n' */
 
 static const char sql_ascii_class[] = {
 /*       x0  x1  x2  x3  x4  x5  x6  x7  x8 x9  xa xb  xc xd xe  xf */
-/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7,  7, 7, 7, 7, 27, 27,
+/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 28, 7, 7, 7, 27, 27,
 /* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
 /* 2x */ 7, 15, 9, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
 /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
@@ -192,12 +193,24 @@ sql_token(const char *z, int *type, bool *is_reserved)
 		i = 1 + sql_skip_spaces(z+1);
 		*type = TK_SPACE;
 		return i;
+	case CC_LINEFEED:
+		*type = TK_LINEFEED;
+		return 1;
 	case CC_MINUS:
+		/*
+		 * Ignore single-line comment started with "--"
+		 * till the end of parsing string or next line.
+		 */
 		if (z[1] == '-') {
-			for (i = 2; (c = z[i]) != 0 && c != '\n'; i++) {
+			for (i = 2; true; i++) {
+				if (z[i] == '\0') {
+					*type = TK_SPACE;
+					return i;
+				} else if (z[i] == '\n') {
+					*type = TK_LINEFEED;
+					return ++i;
+				}
 			}
-			*type = TK_SPACE;
-			return i;
 		}
 		*type = TK_MINUS;
 		return 1;
@@ -499,12 +512,26 @@ sqlRunParser(Parse * pParse, const char *zSql)
 			assert(tokenType == TK_SPACE
 			       || tokenType == TK_ILLEGAL);
 			if (tokenType == TK_ILLEGAL) {
-				diag_set(ClientError, ER_SQL_UNKNOWN_TOKEN,
-					 pParse->sLastToken.n,
-					 pParse->sLastToken.z);
+				if (!pParse->parse_only) {
+					diag_set(ClientError,
+						 ER_SQL_UNKNOWN_TOKEN_WITH_POS,
+						 pParse->line_count,
+						 pParse->line_pos,
+						 pParse->sLastToken.n,
+						 pParse->sLastToken.z);
+				} else {
+					diag_set(ClientError,
+						 ER_SQL_UNKNOWN_TOKEN,
+						 pParse->sLastToken.n,
+						 pParse->sLastToken.z);
+				}
 				pParse->is_aborted = true;
 				break;
 			}
+		} else if (tokenType == TK_LINEFEED) {
+			pParse->line_count++;
+			pParse->line_pos = 1;
+			continue;
 		} else {
 			sqlParser(pEngine, tokenType, pParse->sLastToken,
 				      pParse);
@@ -512,6 +539,7 @@ sqlRunParser(Parse * pParse, const char *zSql)
 			if (pParse->is_aborted || db->mallocFailed)
 				break;
 		}
+		pParse->line_pos += pParse->sLastToken.n;
 	}
 	pParse->zTail = &zSql[i];
 	sqlParserFree(pEngine, sql_free);
diff --git a/test/sql-tap/alter2.test.lua b/test/sql-tap/alter2.test.lua
index e0bd60727..9f53ab86a 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, "Keyword 'REFERENCES' is reserved. Please use double quotes if 'REFERENCES' is an identifier."
+        1, "Syntax error on line 1 at column 57: keyword 'REFERENCES' is reserved. Please use double quotes if 'REFERENCES' is an identifier."
         -- </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, "Syntax error near '('"
+        1, "Syntax error on line 1 at column 45 near '('"
         -- </alter2-4.2>
     })
 
diff --git a/test/sql-tap/blob.test.lua b/test/sql-tap/blob.test.lua
index 2b5c7a9ca..e5d88eef9 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, [[Syntax error: unrecognized token: 'X'01020k304'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'X'01020k304'']]
         -- </blob-1.4>
     })
 
@@ -81,7 +81,7 @@ test:do_catchsql_test(
     [[
         SELECT X'01020, 100]], {
         -- <blob-1.5>
-        1, [[Syntax error: unrecognized token: 'X'01020, 100']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'X'01020, 100']]
         -- </blob-1.5>
     })
 
@@ -91,7 +91,7 @@ test:do_catchsql_test(
         SELECT X'01020 100'
     ]], {
         -- <blob-1.6>
-        1, [[Syntax error: unrecognized token: 'X'01020 100'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'X'01020 100'']]
         -- </blob-1.6>
     })
 
@@ -101,7 +101,7 @@ test:do_catchsql_test(
         SELECT X'01001'
     ]], {
         -- <blob-1.7>
-        1, [[Syntax error: unrecognized token: 'X'01001'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'X'01001'']]
         -- </blob-1.7>
     })
 
@@ -111,7 +111,7 @@ test:do_catchsql_test(
         SELECT x'012/45'
     ]], {
         -- <blob-1.8>
-        1, [[Syntax error: unrecognized token: 'x'012/45'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'x'012/45'']]
         -- </blob-1.8>
     })
 
@@ -121,7 +121,7 @@ test:do_catchsql_test(
         SELECT x'012:45'
     ]], {
         -- <blob-1.9>
-        1, [[Syntax error: unrecognized token: 'x'012:45'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'x'012:45'']]
         -- </blob-1.9>
     })
 
@@ -131,7 +131,7 @@ test:do_catchsql_test(
         SELECT x'012 at 45'
     ]], {
         -- <blob-1.10>
-        1, [[Syntax error: unrecognized token: 'x'012 at 45'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'x'012 at 45'']]
         -- </blob-1.10>
     })
 
@@ -141,7 +141,7 @@ test:do_catchsql_test(
         SELECT x'012G45'
     ]], {
         -- <blob-1.11>
-        1, [[Syntax error: unrecognized token: 'x'012G45'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'x'012G45'']]
         -- </blob-1.11>
     })
 
@@ -151,7 +151,7 @@ test:do_catchsql_test(
         SELECT x'012`45'
     ]], {
         -- <blob-1.12>
-        1, [[Syntax error: unrecognized token: 'x'012`45'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'x'012`45'']]
         -- </blob-1.12>
     })
 
@@ -161,7 +161,7 @@ test:do_catchsql_test(
         SELECT x'012g45'
     ]], {
         -- <blob-1.13>
-        1, [[Syntax error: unrecognized token: 'x'012g45'']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: 'x'012g45'']]
         -- </blob-1.13>
     })
 
diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua
index c9b60bbf5..3be04457e 100755
--- a/test/sql-tap/check.test.lua
+++ b/test/sql-tap/check.test.lua
@@ -282,7 +282,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-2.10>
-        1,"Syntax error near ','"
+        1,"Syntax error on line 2 at column 77 near ','"
         -- </check-2.10>
     })
 
@@ -296,7 +296,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-2.10>
-        1,"Syntax error near ','"
+        1,"Syntax error on line 3 at column 23 near ','"
         -- </check-2.10>
     })
 
@@ -783,7 +783,7 @@ test:do_catchsql_test(
         ON CONFLICT REPLACE)
     ]], {
         -- <9.1>
-        1, "Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
+        1, "Syntax error on line 2 at column 9: keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
         -- </9.1>
     })
 
@@ -794,7 +794,7 @@ test:do_catchsql_test(
         ON CONFLICT ABORT)
     ]], {
         -- <9.2>
-        1, "Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
+        1, "Syntax error on line 2 at column 9: keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
         -- </9.2>
     })
 
@@ -805,7 +805,7 @@ test:do_catchsql_test(
         ON CONFLICT ROLLBACK)
     ]], {
         -- <9.3>
-        1, "Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
+        1, "Syntax error on line 2 at column 9: keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier."
         -- </9.3>
     })
 
diff --git a/test/sql-tap/count.test.lua b/test/sql-tap/count.test.lua
index cf5bfccdd..3b2d4aa89 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, [[Syntax error near '*']]
+        1, [[Syntax error on line 1 at column 31 near '*']]
         -- </count-2.2>
     })
 
diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua
index f2a5db071..9feca0df1 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, "Syntax error near 'id'"
+    1, "Syntax error on line 1 at column 64 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, "Syntax error near '\"id\"'"
+    1, "Syntax error on line 1 at column 64 near '\"id\"'"
     -- </default-5.3>
 })
 
diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua
index a0a671644..fb790e9f4 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. Please use double quotes if 'ON' is an identifier.]]
+        1, [[Syntax error on line 1 at column 47: keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.]]
         -- </e_select-0.1.5>
     })
 
@@ -805,9 +805,9 @@ test:do_select_tests(
 -- FROM clause.
 --
 data = {
-    {"1.1", "SELECT a, b, c FROM z1 WHERE *",  "Syntax error near '*'"},
-    {"1.2", "SELECT a, b, c FROM z1 GROUP BY *", "Syntax error near '*'"},
-    {"1.3", "SELECT 1 + * FROM z1",  "Syntax error near '*'"},
+    {"1.1", "SELECT a, b, c FROM z1 WHERE *",  "Syntax error on line 1 at column 30 near '*'"},
+    {"1.2", "SELECT a, b, c FROM z1 GROUP BY *", "Syntax error on line 1 at column 33 near '*'"},
+    {"1.3", "SELECT 1 + * FROM z1",  "Syntax error on line 1 at column 12 near '*'"},
     {"1.4", "SELECT * + 1 FROM z1", "Failed to expand '*' in SELECT statement without FROM clause"},
     {"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"},
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 39d9ccf2d..d1c6dc264 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -1882,7 +1882,7 @@ test:do_catchsql_test(
         SELECT trim(1,2,3)
     ]], {
         -- <func-22.1>
-        1, "Syntax error near ','"
+        1, "Syntax error on line 1 at column 22 near ','"
         -- </func-22.1>
     })
 
@@ -2228,7 +2228,7 @@ test:do_catchsql_test(
         SELECT TRIM(FROM 'xyxzy');
     ]], {
         -- <func-22.38>
-        1, "Syntax error near 'FROM'"
+        1, "Syntax error on line 1 at column 21 near 'FROM'"
         -- </func-22.38>
     })
 
diff --git a/test/sql-tap/gh2168-temp-tables.test.lua b/test/sql-tap/gh2168-temp-tables.test.lua
index 3b29c9ed2..8012cf135 100755
--- a/test/sql-tap/gh2168-temp-tables.test.lua
+++ b/test/sql-tap/gh2168-temp-tables.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(2)
+test:plan(3)
 
 test:do_catchsql_test(
 	"trigger2-10.1",
@@ -8,23 +8,32 @@ test:do_catchsql_test(
 		CREATE TEMP TABLE tmp1 (id INTEGER PRIMARY KEY);
 	]], {
 		-- <trigger2-10.1>
-	1, "Syntax error near 'TEMP'"
+	1, "Syntax error on line 1 at column 10 near 'TEMP'"
 		-- <trigger2-10.1>
 });
 
 -- TEMP triggers are removed now, check it
-test:do_catchsql_test(
-	"trigger2-10.1",
+
+test:do_execsql_test(
+	"trigger2-10.2",
 	[[
 		CREATE TABLE t1 (id INTEGER PRIMARY KEY);
+	]], {
+		-- <trigger2-10.2>
+		-- <trigger2-10.2>
+});
+
+test:do_catchsql_test(
+	"trigger2-10.3",
+	[[
 		CREATE TEMP TRIGGER ttmp1 BEFORE UPDATE ON t1
 		BEGIN
 			SELECT 1;
 		END;
 	]], {
-		-- <trigger2-10.1>
-	1, "Syntax error near 'TEMP'"
-		-- <trigger2-10.1>
+		-- <trigger2-10.3>
+	1, "Syntax error on line 1 at column 10 near 'TEMP'"
+		-- <trigger2-10.3>
 });
 
 
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 65ed9aea1..3d70e7457 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -240,7 +240,7 @@ test:do_catchsql_test(
 data = {
     { 1,  [[ 'a' < 'b' collate binary ]], {1, "Collation 'BINARY' does not exist"}},
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
-    { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error near ''binary'']]}},
+    { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error on line 1 at column 43 near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
     { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
     { 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 a5ed9a98e..46c64ba68 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, "Syntax error near '.'",
+        1, "Syntax error on line 1 at column 23 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 16209715d..7b8523555 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, "Syntax error near '.'"
+        1, "Syntax error on line 1 at column 26 near '.'"
         -- </index-21.1>
     })
 
diff --git a/test/sql-tap/index7.test.lua b/test/sql-tap/index7.test.lua
index ca5cb1910..340a5a963 100755
--- a/test/sql-tap/index7.test.lua
+++ b/test/sql-tap/index7.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(11)
+test:plan(12)
 
 --!./tcltestrunner.lua
 -- 2013-11-04
@@ -286,13 +286,18 @@ test:do_eqp_test(
 -- gh-2165 Currently, Tarantool lacks support of partial indexes,
 -- so temporary we removed processing of their syntax from parser.
 --
-test:do_catchsql_test(
+test:do_execsql_test(
     "index7-7.1",
     [[
         CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER);
+    ]])
+
+test:do_catchsql_test(
+    "index7-7.1",
+    [[
         CREATE UNIQUE INDEX i ON t1 (a) WHERE a = 3;
     ]], {
-        1, "Keyword 'WHERE' is reserved. Please use double quotes if 'WHERE' is an identifier."
+        1, "Syntax error on line 1 at column 41: 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/keyword1.test.lua b/test/sql-tap/keyword1.test.lua
index 03b1054d2..ffb18c4fd 100755
--- a/test/sql-tap/keyword1.test.lua
+++ b/test/sql-tap/keyword1.test.lua
@@ -238,11 +238,25 @@ end
 
 for _, kw in ipairs(bannedkws) do
     query = 'CREATE TABLE '..kw..'(a INT PRIMARY KEY);'
-    test:do_catchsql_test(
+    if kw == 'end' or kw == 'match' or kw == 'release' or kw == 'rename' or
+       kw == 'replace' or kw == 'binary' or kw == 'character' or
+       kw == 'smallint' then
+        test:do_catchsql_test(
         "bannedkw1-"..kw..".1",
         query, {
-            1, "Keyword '"..kw.."' is reserved. Please use double quotes if '"..kw.."' is an identifier."
+            1, "Syntax error on line 1 at column "..14 + string.len(kw)..
+            ": keyword '"..kw.."' is reserved. Please use double quotes if '"
+            ..kw.."' is an identifier."
         })
+    else
+        test:do_catchsql_test(
+        "bannedkw1-"..kw..".1",
+        query, {
+            1, "Syntax error on line 1 at column 14: keyword '"..kw..
+            "' is reserved. Please use double quotes if '"..kw..
+            "' is an identifier."
+        })
+    end
 end
 
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index b84093e3c..ae7829ff8 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(58)
+test:plan(59)
 
 --!./tcltestrunner.lua
 -- 2001 September 15.
@@ -262,17 +262,26 @@ test:do_execsql_test(
 -- before executing a command.  Thus if "WHERE" is misspelled on an UPDATE,
 -- the user won't accidently update every record.
 --
-test:do_catchsql_test(
-    "misc1-5.1",
+
+test:do_execsql_test(
+    "misc1-5.1.1",
     [[
         CREATE TABLE t3(a  INT primary key,b INT );
         INSERT INTO t3 VALUES(1,2);
         INSERT INTO t3 VALUES(3,4);
+    ]], {
+        -- <misc1-5.1.1>
+        -- </misc1-5.1.1>
+    })
+
+test:do_catchsql_test(
+    "misc1-5.1.2",
+    [[
         UPDATE t3 SET a=0 WHEREwww b=2;
     ]], {
-        -- <misc1-5.1>
-        1, [[Syntax error near 'WHEREwww']]
-        -- </misc1-5.1>
+        -- <misc1-5.1.2>
+        1, [[Syntax error on line 1 at column 27 near 'WHEREwww']]
+        -- </misc1-5.1.2>
     })
 
 test:do_execsql_test(
@@ -1037,7 +1046,7 @@ test:do_catchsql_test(
         select''like''like''like#0;
     ]], {
         -- <misc1-21.1>
-        1, [[Syntax error near '#0']]
+        1, [[Syntax error on line 1 at column 35 near '#0']]
         -- </misc1-21.1>
     })
 
@@ -1047,7 +1056,7 @@ test:do_catchsql_test(
         VALUES(0,0x0MATCH#0;
     ]], {
         -- <misc1-21.2>
-        1, [[Syntax error near '#0']]
+        1, [[Syntax error on line 1 at column 28 near '#0']]
         -- </misc1-21.2>
     })
 
diff --git a/test/sql-tap/misc5.test.lua b/test/sql-tap/misc5.test.lua
index 5f98f21f6..33ad8c3bb 100755
--- a/test/sql-tap/misc5.test.lua
+++ b/test/sql-tap/misc5.test.lua
@@ -347,7 +347,7 @@ test:do_catchsql_test(
         SELECT 123abc
     ]], {
         -- <misc5-10.1>
-        1, [[Syntax error: unrecognized token: '123abc']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '123abc']]
         -- </misc5-10.1>
     })
 
@@ -357,7 +357,7 @@ test:do_catchsql_test(
         SELECT 1*123.4e5ghi;
     ]], {
         -- <misc5-10.2>
-        1, [[Syntax error: unrecognized token: '123.4e5ghi']]
+        1, [[Syntax error on line 1 at column 18 unrecognized token: '123.4e5ghi']]
         -- </misc5-10.2>
     })
 
diff --git a/test/sql-tap/null.test.lua b/test/sql-tap/null.test.lua
index de4d5033d..feb3601be 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, "Syntax error near '1'"
+    1, "Syntax error on line 1 at column 29 near '1'"
     -- <index-1.3>
     })
 
@@ -528,7 +528,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "Syntax error near '1'"
+    1, "Syntax error on line 1 at column 33 near '1'"
     -- <index-1.3>
     })
 
@@ -539,7 +539,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "Syntax error near '1'"
+    1, "Syntax error on line 1 at column 32 near '1'"
     -- <index-1.3>
     })
 
@@ -550,7 +550,7 @@ test:do_catchsql_test(
     ]],
     {
     -- <index-1.3>
-    1, "Syntax error near '1'"
+    1, "Syntax error on line 1 at column 36 near '1'"
     -- <index-1.3>
     })
 
diff --git a/test/sql-tap/pragma.test.lua b/test/sql-tap/pragma.test.lua
index b3821dcf7..fcd3c2e0b 100755
--- a/test/sql-tap/pragma.test.lua
+++ b/test/sql-tap/pragma.test.lua
@@ -43,7 +43,7 @@ test:do_catchsql_test(
 	[[
 		pragma sql_default_engine 'memtx';
 	]], {
-	1, "Syntax error near ''memtx''"
+	1, "Syntax error on line 1 at column 29 near ''memtx''"
 })
 
 test:do_catchsql_test(
@@ -51,7 +51,7 @@ test:do_catchsql_test(
 	[[
 		pragma sql_default_engine 1;
 	]], {
-	1, "Syntax error near '1'"
+	1, "Syntax error on line 1 at column 29 near '1'"
 })
 
 --
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index 4bbfbd67b..ff45b8b28 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, [[Syntax error near ';']]
+        1, [[Syntax error on line 1 at column 39 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. Please use double quotes if 'WHERE' is an identifier.]]
+            1, [[Syntax error on line 1 at column 47: 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. Please use double quotes if 'as' is an identifier.]]
+        1, [[Syntax error on line 1 at column 47: 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, [[Syntax error near ';']]
+        1, [[Syntax error on line 1 at column 38 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. Please use double quotes if 'where' is an identifier.]]
+        1, [[Syntax error on line 1 at column 51: 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. Please use double quotes if 'FROM' is an identifier.]]
+        1, [[Syntax error on line 1 at column 28: 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, [[Syntax error near ')']]
+        1, [[Syntax error on line 1 at column 28 near ')']]
         -- </select1-7.7>
     })
 
@@ -1478,7 +1478,7 @@ test:do_catchsql_test(
         SELECT f1 FROM test1 ORDER BY f2, f1+;
     ]], {
         -- <select1-7.8>
-        1, [[Syntax error near ';']]
+        1, [[Syntax error on line 1 at column 46 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. Please use double quotes if 'ORDER' is an identifier.]]
+        1, [[Syntax error on line 1 at column 50: keyword 'ORDER' is reserved. Please use double quotes if 'ORDER' is an identifier.]]
         -- </select1-7.9>
     })
 
diff --git a/test/sql-tap/select3.test.lua b/test/sql-tap/select3.test.lua
index 19f853dc7..8b6f8f482 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. Please use double quotes if 'ORDER' is an identifier.]]
+  1, [[Syntax error on line 1 at column 41: 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, [[Syntax error near ';']]
+  1, [[Syntax error on line 1 at column 40 near ';']]
   -- </select3-2.14>
 })
 
diff --git a/test/sql-tap/sql-errors.test.lua b/test/sql-tap/sql-errors.test.lua
index cb8952424..9f8e75aab 100755
--- a/test/sql-tap/sql-errors.test.lua
+++ b/test/sql-tap/sql-errors.test.lua
@@ -17,7 +17,7 @@ test:do_catchsql_test(
 		ANALYZE v0;
 	]], {
 		-- <sql-errors-1.1>
-		1,"Syntax error near 'ANALYZE'"
+		1,"Syntax error on line 1 at column 3 near 'ANALYZE'"
 		-- </sql-errors-1.1>
 	})
 
@@ -422,7 +422,7 @@ test:do_catchsql_test(
 		CREATE TRIGGER r0 AFTER INSERT ON t0 FOR EACH ROW BEGIN INSERT INTO t0.i VALUES (2); END;
 	]], {
 		-- <sql-errors-1.37>
-		1,"qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers"
+		1,"Syntax error on line 1 at column 76: qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers"
 		-- </sql-errors-1.37>
 	})
 
@@ -522,7 +522,7 @@ test:do_catchsql_test(
 		DROP TABLE IF EXISTS END;
 	]], {
 		-- <sql-errors-1.47>
-		1, "Keyword 'END' is reserved. Please use double quotes if 'END' is an identifier."
+		1, "Syntax error on line 1 at column 27: keyword 'END' is reserved. Please use double quotes if 'END' is an identifier."
 		-- </sql-errors-1.47>
 	})
 
diff --git a/test/sql-tap/start-transaction.test.lua b/test/sql-tap/start-transaction.test.lua
index c5703d438..b2cd9a1b9 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, "Syntax error near 'BEGIN'"
+		1, "Syntax error on line 2 at column 3 near 'BEGIN'"
 		-- <start-transaction-1.0>
 	})
 
@@ -46,7 +46,7 @@ test:do_catchsql_test(
 		COMMIT;
 	]], {
 		-- <start-transaction-1.1>
-		1, "Syntax error near 'BEGIN'"
+		1, "Syntax error on line 2 at column 3 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. Please use double quotes if 'TRANSACTION' is an identifier."
+		1, "Syntax error on line 2 at column 10: 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. Please use double quotes if 'END' is an identifier."
+		1, "Syntax error on line 2 at column 3: 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. Please use double quotes if 'END' is an identifier."
+		1, "Syntax error on line 2 at column 3: 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. Please use double quotes if 'TRANSACTION' is an identifier."
+		1, "Syntax error on line 2 at column 13: 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. Please use double quotes if 'TRANSACTION' is an identifier."
+		1, "Syntax error on line 2 at column 13: 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 e17b4a2c1..4616a82a6 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, "Syntax error near 'TEMP'"
+	1, "Syntax error on line 1 at column 10 near 'TEMP'"
 	-- <temp>
 	})
 
@@ -630,7 +630,7 @@ test:do_catchsql_test(
 		CREATE TEMPORARY TABLE t1(a INTEGER PRIMARY KEY, b VARCHAR(10));
 	]], {
 	-- <temporary>
-	1, "Syntax error near 'TEMPORARY'"
+	1, "Syntax error on line 1 at column 10 near 'TEMPORARY'"
 	-- <temporary>
 	})
 
@@ -1257,7 +1257,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <table-22.1>
-        1,"Keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
+        1,"Syntax error on line 3 at column 28: keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
         -- </table-22.1>
     })
 
@@ -1322,7 +1322,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <table-22.6>
-        1,"Keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
+        1,"Syntax error on line 3 at column 37: keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
         -- </table-22.6>
     })
 
@@ -1336,7 +1336,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <table-22.7>
-        1,"Keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
+        1,"Syntax error on line 3 at column 37: keyword 'CONSTRAINT' is reserved. Please use double quotes if 'CONSTRAINT' is an identifier."
         -- </table-22.7>
     })
 
diff --git a/test/sql-tap/tokenize.test.lua b/test/sql-tap/tokenize.test.lua
index b1a097e23..eb11eb8a4 100755
--- a/test/sql-tap/tokenize.test.lua
+++ b/test/sql-tap/tokenize.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(14)
+test:plan(16)
 
 --!./tcltestrunner.lua
 -- 2008 July 7
@@ -26,7 +26,7 @@ test:do_catchsql_test(
         SELECT 1.0e+
     ]], {
         -- <tokenize-1.1>
-        1, [[Syntax error: unrecognized token: '1.0e']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0e']]
         -- </tokenize-1.1>
     })
 
@@ -36,7 +36,7 @@ test:do_catchsql_test(
         SELECT 1.0E+
     ]], {
         -- <tokenize-1.2>
-        1, [[Syntax error: unrecognized token: '1.0E']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0E']]
         -- </tokenize-1.2>
     })
 
@@ -46,7 +46,7 @@ test:do_catchsql_test(
         SELECT 1.0e-
     ]], {
         -- <tokenize-1.3>
-        1, [[Syntax error: unrecognized token: '1.0e']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0e']]
         -- </tokenize-1.3>
     })
 
@@ -56,7 +56,7 @@ test:do_catchsql_test(
         SELECT 1.0E-
     ]], {
         -- <tokenize-1.4>
-        1, [[Syntax error: unrecognized token: '1.0E']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0E']]
         -- </tokenize-1.4>
     })
 
@@ -66,7 +66,7 @@ test:do_catchsql_test(
         SELECT 1.0e+/
     ]], {
         -- <tokenize-1.5>
-        1, [[Syntax error: unrecognized token: '1.0e']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0e']]
         -- </tokenize-1.5>
     })
 
@@ -76,7 +76,7 @@ test:do_catchsql_test(
         SELECT 1.0E+:
     ]], {
         -- <tokenize-1.6>
-        1, [[Syntax error: unrecognized token: '1.0E']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0E']]
         -- </tokenize-1.6>
     })
 
@@ -86,7 +86,7 @@ test:do_catchsql_test(
         SELECT 1.0e-:
     ]], {
         -- <tokenize-1.7>
-        1, [[Syntax error: unrecognized token: '1.0e']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0e']]
         -- </tokenize-1.7>
     })
 
@@ -96,7 +96,7 @@ test:do_catchsql_test(
         SELECT 1.0E-/
     ]], {
         -- <tokenize-1.8>
-        1, [[Syntax error: unrecognized token: '1.0E']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0E']]
         -- </tokenize-1.8>
     })
 
@@ -106,7 +106,7 @@ test:do_catchsql_test(
         SELECT 1.0F+5
     ]], {
         -- <tokenize-1.9>
-        1, [[Syntax error: unrecognized token: '1.0F']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0F']]
         -- </tokenize-1.9>
     })
 
@@ -116,7 +116,7 @@ test:do_catchsql_test(
         SELECT 1.0d-10
     ]], {
         -- <tokenize-1.10>
-        1, [[Syntax error: unrecognized token: '1.0d']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0d']]
         -- </tokenize-1.10>
     })
 
@@ -126,7 +126,7 @@ test:do_catchsql_test(
         SELECT 1.0e,5
     ]], {
         -- <tokenize-1.11>
-        1, [[Syntax error: unrecognized token: '1.0e']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0e']]
         -- </tokenize-1.11>
     })
 
@@ -136,7 +136,7 @@ test:do_catchsql_test(
         SELECT 1.0E.10
     ]], {
         -- <tokenize-1.12>
-        1, [[Syntax error: unrecognized token: '1.0E']]
+        1, [[Syntax error on line 1 at column 16 unrecognized token: '1.0E']]
         -- </tokenize-1.12>
     })
 
@@ -145,7 +145,7 @@ test:do_catchsql_test(
     [[
         SELECT 1, 2 /*]], {
         -- <tokenize-2.1>
-        1, [[Syntax error near '*']]
+        1, [[Syntax error on line 1 at column 22 near '*']]
         -- </tokenize-2.1>
     })
 
@@ -159,6 +159,29 @@ test:do_catchsql_test(
         -- </tokenize-2.2>
     })
 
+--
+--gh-2611 Check the correct parsing of single-line comments.
+--
+test:do_execsql_test(
+    "tokenize-3.1",
+    [[
+        SELECT 1 + -- 1 + 1.
+        1
+    ]], {
+        -- <tokenize-2.2>
+        2
+        -- </tokenize-2.2>
+    })
 
+test:do_catchsql_test(
+    "tokenize-3.2",
+    [[
+        SELECT 1 + -- Syntax error.
+        *
+    ]], {
+        -- <tokenize-2.2>
+        1,"Syntax error on line 2 at column 9 near '*'"
+        -- </tokenize-2.2>
+    })
 
 test:finish_test()
diff --git a/test/sql-tap/trigger1.test.lua b/test/sql-tap/trigger1.test.lua
index bc02d6236..20bc8f1b7 100755
--- a/test/sql-tap/trigger1.test.lua
+++ b/test/sql-tap/trigger1.test.lua
@@ -74,7 +74,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-1.1.3>
-        1, [[Syntax error near 'STATEMENT']]
+        1, [[Syntax error on line 1 at column 51 near 'STATEMENT']]
         -- </trigger1-1.1.3>
     })
 
@@ -307,7 +307,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-2.1>
-        1, [[Syntax error near ';']]
+        1, [[Syntax error on line 3 at column 24 near ';']]
         -- </trigger1-2.1>
     })
 
@@ -321,7 +321,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-2.2>
-        1, [[Syntax error near ';']]
+        1, [[Syntax error on line 4 at column 24 near ';']]
         -- </trigger1-2.2>
     })
 
@@ -823,7 +823,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.4>
-        1, "Syntax error in trigger body: the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error on line 2 at column 34 in trigger body: the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.4>
     })
 
@@ -835,7 +835,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.5>
-        1, "Syntax error in trigger body: the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error on line 2 at column 38 in trigger body: the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.5>
     })
 
@@ -847,7 +847,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.6>
-        1, "Syntax error in trigger body: the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error on line 2 at column 39 in trigger body: the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers"
         -- </trigger1-16.6>
     })
 
@@ -859,7 +859,7 @@ test:do_catchsql_test(
         END;
     ]], {
         -- <trigger1-16.7>
-        1, "Syntax error in trigger body: the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers"
+        1, "Syntax error on line 2 at column 43 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 6234f863e..d094eec0a 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. Please use double quotes if 'DESC' is an identifier.]]
+        1, [[Syntax error on line 1 at column 31: keyword 'DESC' is reserved. Please use double quotes if 'DESC' is an identifier.]]
         -- </view-3.3.4>
     })
 
diff --git a/test/sql-tap/with1.test.lua b/test/sql-tap/with1.test.lua
index f82b73e63..1b2300882 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. Please use double quotes if 'SELECT' is an identifier.]]
+  1, [[Syntax error on line 2 at column 3: keyword 'SELECT' is reserved. Please use double quotes if 'SELECT' is an identifier.]]
   -- </3.6>
 })
 
diff --git a/test/sql-tap/with2.test.lua b/test/sql-tap/with2.test.lua
index 8c7f9f2d9..edbc17c0d 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, [[Syntax error near ')']]
+    1, [[Syntax error on line 1 at column 12 near ')']]
     -- </4.1>
 })
 
@@ -519,7 +519,7 @@ test:do_catchsql_test(6.2, [[
     INSERT INTO t2 VALUES(1, 2,);
 ]], {
     -- <6.2>
-    1, [[Syntax error near ')']]
+    1, [[Syntax error on line 2 at column 32 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. Please use double quotes if 'FROM' is an identifier.]]
+    1, [[Syntax error on line 2 at column 33: 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. Please use double quotes if 'FROM' is an identifier.]]
+    1, [[Syntax error on line 2 at column 33: 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, [[Syntax error near ';']]
+    1, [[Syntax error on line 2 at column 25 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, "Syntax error near '\n'"
+    1, "Syntax error on line 2 at column 1 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, "Syntax error near 'WHRE'"
+    1, "Syntax error on line 1 at column 49 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, "Syntax error near ';'"
+    1, "Syntax error on line 1 at column 60 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, "Syntax error near '='"
+    1, "Syntax error on line 1 at column 71 near '='"
     -- </6.9>
 })
 
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 50347bc3a..4ef888c6a 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -42,6 +42,16 @@ box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5'})
 - error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error near
     ''<'''
 ...
+box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', '1.0E+'})
+---
+- error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error: unrecognized
+    token: ''1.0E'''
+...
+box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'CREATE'})
+---
+- error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Keyword ''CREATE''
+    is reserved. Please use double quotes if ''CREATE'' is an identifier.'
+...
 -- Non-existent space test.
 box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'})
 ---
@@ -160,7 +170,7 @@ box.execute("DROP TABLE t1")
 box.execute("CREATE TABLE first (id NUMBER PRIMARY KEY CHECK(id < 5), a INT CONSTRAINT ONE CHECK(a >< 5));")
 ---
 - null
-- Syntax error near '<'
+- Syntax error on line 1 at column 88 near '<'
 ...
 box.space.FIRST == nil
 ---
diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua
index cde213f8b..3dd3fb5ce 100644
--- a/test/sql/checks.test.lua
+++ b/test/sql/checks.test.lua
@@ -19,6 +19,8 @@ _ = box.space.test:create_index('pk')
 
 -- Invalid expression test.
 box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5'})
+box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', '1.0E+'})
+box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'CREATE'})
 -- Non-existent space test.
 box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'})
 -- Pass integer instead of expression.
diff --git a/test/sql/engine.result b/test/sql/engine.result
index 3ee93ad19..58b9dacb1 100644
--- a/test/sql/engine.result
+++ b/test/sql/engine.result
@@ -104,12 +104,12 @@ box.space.T2_MEMTX:drop()
 box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE = VINYL")
 ---
 - null
-- Syntax error near 'VINYL'
+- Syntax error on line 1 at column 58 near 'VINYL'
 ...
 box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE = vinyl")
 ---
 - null
-- Syntax error near 'vinyl'
+- Syntax error on line 1 at column 58 near 'vinyl'
 ...
 box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE = 'VINYL'")
 ---
@@ -119,7 +119,7 @@ box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE = 'VINYL'")
 box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE = \"vinyl\"")
 ---
 - null
-- Syntax error near '"vinyl"'
+- Syntax error on line 1 at column 58 near '"vinyl"'
 ...
 -- Make sure that wrong engine name is handled properly.
 --
diff --git a/test/sql/foreign-keys.result b/test/sql/foreign-keys.result
index 29538e816..f17234904 100644
--- a/test/sql/foreign-keys.result
+++ b/test/sql/foreign-keys.result
@@ -396,22 +396,26 @@ box.execute('CREATE TABLE t1 (id INT PRIMARY KEY);')
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE RESTRICT);')
 ---
 - null
-- Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an identifier.
+- 'Syntax error on line 1 at column 72: keyword ''DELETE'' is reserved. Please use
+  double quotes if ''DELETE'' is an identifier.'
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON DELETE CASCADE);')
 ---
 - null
-- Keyword 'DELETE' is reserved. Please use double quotes if 'DELETE' is an identifier.
+- 'Syntax error on line 1 at column 72: keyword ''DELETE'' is reserved. Please use
+  double quotes if ''DELETE'' is an identifier.'
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE ON UPDATE RESTRICT ON DELETE RESTRICT);')
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 88: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute('CREATE TABLE t2 (id INT PRIMARY KEY REFERENCES t2 ON DELETE CASCADE MATCH FULL);')
 ---
 - null
-- Keyword 'MATCH' is reserved. Please use double quotes if 'MATCH' is an identifier.
+- 'Syntax error on line 1 at column 69: 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 4b8e7ede6..f20598e4a 100644
--- a/test/sql/gh-3888-values-blob-assert.result
+++ b/test/sql/gh-3888-values-blob-assert.result
@@ -18,23 +18,23 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 box.execute('VALUES(scalar)')
 ---
 - null
-- Syntax error near 'scalar'
+- Syntax error on line 1 at column 8 near 'scalar'
 ...
 box.execute('VALUES(float)')
 ---
 - null
-- Syntax error near 'float'
+- Syntax error on line 1 at column 8 near 'float'
 ...
 -- check 'SELECT' against typedef keywords (should fail)
 box.execute('SELECT scalar')
 ---
 - null
-- Syntax error near 'scalar'
+- Syntax error on line 1 at column 8 near 'scalar'
 ...
 box.execute('SELECT float')
 ---
 - null
-- Syntax error near 'float'
+- Syntax error on line 1 at column 8 near 'float'
 ...
 -- check 'VALUES' against ID (should fail)
 box.execute('VALUES(TheColumnName)')
diff --git a/test/sql/iproto.result b/test/sql/iproto.result
index 1e5c30aec..fcbae53ce 100644
--- a/test/sql/iproto.result
+++ b/test/sql/iproto.result
@@ -106,7 +106,7 @@ cn:execute('insert into not_existing_table values ("kek")')
 ...
 cn:execute('insert qwerty gjsdjq  q  qwd qmq;; q;qwd;')
 ---
-- error: Syntax error near 'qwerty'
+- error: Syntax error on line 1 at column 8 near 'qwerty'
 ...
 -- Empty result.
 cn:execute('select id as identifier from test where a = 5;')
@@ -119,7 +119,7 @@ cn:execute('select id as identifier from test where a = 5;')
 -- netbox API errors.
 cn:execute(100)
 ---
-- error: Syntax error near '100'
+- error: Syntax error on line 1 at column 1 near '100'
 ...
 cn:execute('select 1', nil, {dry_run = true})
 ---
@@ -352,7 +352,7 @@ cn:execute('drop table if exists test3')
 --
 cn:execute('select ?1, ?2, ?3', {1, 2, 3})
 ---
-- error: Syntax error near '?1'
+- error: Syntax error on line 1 at column 10 near '?1'
 ...
 cn:execute('select $name, $name2', {1, 2})
 ---
diff --git a/test/sql/misc.result b/test/sql/misc.result
index a157ddbc1..82b86f574 100644
--- a/test/sql/misc.result
+++ b/test/sql/misc.result
@@ -20,12 +20,14 @@ box.execute('select 1;')
 box.execute('select 1; select 2;')
 ---
 - null
-- Keyword 'select' is reserved. Please use double quotes if 'select' is an identifier.
+- 'Syntax error on line 1 at column 11: keyword ''select'' is reserved. Please use
+  double quotes if ''select'' is an identifier.'
 ...
 box.execute('create table t1 (id INT primary key); select 100;')
 ---
 - null
-- Keyword 'select' is reserved. Please use double quotes if 'select' is an identifier.
+- 'Syntax error on line 1 at column 39: keyword ''select'' is reserved. Please use
+  double quotes if ''select'' is an identifier.'
 ...
 box.space.t1 == nil
 ---
@@ -56,17 +58,20 @@ box.execute('\n\n\n\t\t\t   ')
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b INTEGER CONSTRAINT c1 NULL)')
 ---
 - null
-- Keyword 'NULL' is reserved. Please use double quotes if 'NULL' is an identifier.
+- 'Syntax error on line 1 at column 68: keyword ''NULL'' is reserved. Please use double
+  quotes if ''NULL'' is an identifier.'
 ...
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b INTEGER CONSTRAINT c1 DEFAULT 300)')
 ---
 - null
-- Keyword 'DEFAULT' is reserved. Please use double quotes if 'DEFAULT' is an identifier.
+- 'Syntax error on line 1 at column 68: keyword ''DEFAULT'' is reserved. Please use
+  double quotes if ''DEFAULT'' is an identifier.'
 ...
 box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, b TEXT CONSTRAINT c1 COLLATE "binary")')
 ---
 - null
-- Keyword 'COLLATE' is reserved. Please use double quotes if 'COLLATE' is an identifier.
+- 'Syntax error on line 1 at column 65: keyword ''COLLATE'' is reserved. Please use
+  double quotes if ''COLLATE'' is an identifier.'
 ...
 -- Make sure that type of literals in meta complies with its real
 -- type. For instance, typeof(0.5) is number, not integer.
diff --git a/test/sql/on-conflict.result b/test/sql/on-conflict.result
index 6851e217e..328656ea1 100644
--- a/test/sql/on-conflict.result
+++ b/test/sql/on-conflict.result
@@ -15,44 +15,52 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 box.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT ABORT)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 58: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute("CREATE TABLE q (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT FAIL)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 58: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute("CREATE TABLE p (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT IGNORE)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 58: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute("CREATE TABLE g (id INTEGER PRIMARY KEY, v INTEGER UNIQUE ON CONFLICT REPLACE)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 58: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute("CREATE TABLE e (id INTEGER PRIMARY KEY ON CONFLICT REPLACE, v INTEGER)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 40: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute("CREATE TABLE t1(a INT PRIMARY KEY ON CONFLICT REPLACE)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 35: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 box.execute("CREATE TABLE t2(a INT PRIMARY KEY ON CONFLICT IGNORE)")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 35: keyword ''ON'' is reserved. Please use double
+  quotes if ''ON'' is an identifier.'
 ...
 -- CHECK constraint is illegal with REPLACE option.
 --
 box.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER CHECK (a > 5) ON CONFLICT REPLACE);")
 ---
 - null
-- Keyword 'ON' is reserved. Please use double quotes if 'ON' is an identifier.
+- 'Syntax error on line 1 at column 65: 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/triggers.result b/test/sql/triggers.result
index 9dfe981a0..8e0e60edc 100644
--- a/test/sql/triggers.result
+++ b/test/sql/triggers.result
@@ -513,7 +513,8 @@ space_id = box.space.T1.id
 box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN ; END;")
 ---
 - null
-- FOR EACH STATEMENT triggers are not implemented, please supply FOR EACH ROW clause
+- 'Syntax error on line 1 at column 39: FOR EACH STATEMENT triggers are not implemented,
+  please supply FOR EACH ROW clause'
 ...
 box.execute("DROP TABLE t1;")
 ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 1bb8b0cec..e4f317ed6 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -9,27 +9,30 @@ test_run = env.new()
 box.execute("CREATE TABLE t1 (id PRIMARY KEY);")
 ---
 - null
-- Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an identifier.
+- 'Syntax error on line 1 at column 21: keyword ''PRIMARY'' is reserved. Please use
+  double quotes if ''PRIMARY'' is an identifier.'
 ...
 box.execute("CREATE TABLE t1 (a, id INT PRIMARY KEY);")
 ---
 - null
-- Syntax error near ','
+- Syntax error on line 1 at column 19 near ','
 ...
 box.execute("CREATE TABLE t1 (id PRIMARY KEY, a INT);")
 ---
 - null
-- Keyword 'PRIMARY' is reserved. Please use double quotes if 'PRIMARY' is an identifier.
+- 'Syntax error on line 1 at column 21: keyword ''PRIMARY'' is reserved. Please use
+  double quotes if ''PRIMARY'' is an identifier.'
 ...
 box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a);")
 ---
 - null
-- Syntax error near ')'
+- Syntax error on line 1 at column 39 near ')'
 ...
 box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b UNIQUE);")
 ---
 - null
-- Keyword 'UNIQUE' is reserved. Please use double quotes if 'UNIQUE' is an identifier.
+- 'Syntax error on line 1 at column 47: keyword ''UNIQUE'' is reserved. Please use
+  double quotes if ''UNIQUE'' is an identifier.'
 ...
 -- gh-3104: real type is stored in space format.
 --




More information about the Tarantool-patches mailing list