From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 0ADD043D678 for ; Wed, 23 Oct 2019 13:40:36 +0300 (MSK) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 13.0 \(3594.4.19\)) From: Roman Khabibov In-Reply-To: <20191014154750.GA21135@tarantool.org> Date: Wed, 23 Oct 2019 13:40:34 +0300 Content-Transfer-Encoding: quoted-printable Message-Id: References: <20191006210514.49639-1-roman.habibov@tarantool.org> <20191014154750.GA21135@tarantool.org> Subject: Re: [Tarantool-patches] [tarantool-patches] [PATCH] sql: print line and column number in error message List-Id: Tarantool development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "n. pettik" Cc: tarantool-patches@dev.tarantool.org Hi! Thanks for the review. > On Oct 14, 2019, at 18:47, Nikita Pettik = wrote: >=20 > 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. >>=20 >> Closes #2611 >>=20 >> # Please enter the commit message for your changes. Lines starting >=20 > ? 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") \ >=20 > What about other syntax related errors like ER_SQL_PARSER_GENERIC, > ER_SQL_SYNTAX? Please use the same pattern for all errors: >=20 > "On line %d at/near position %d ..." OR > "Syntax error on line %d at column %d: =E2=80=A6=E2=80=9D 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 =3D db; >> parser->sql_flags =3D sql_flags; >> + parser->line_count =3D 1; >> + parser->offset_count =3D 1; >> region_create(&parser->region, &cord()->slabc); >> } >>=20 >> 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 { >> = ***********************************************************************/ >>=20 >> Token sLastToken; /* The last token parsed */ >> + int line_count; /* The line counter. */ >> + int offset_count; /* The offset counter. */ >=20 > 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 { = ***********************************************************************/ =20 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 =3D 1 + sql_skip_spaces(z+1); >> *type =3D TK_SPACE; >> return i; >> + case CC_LINEFEED: >> + *type =3D TK_LINEFEED; >> + return 1; >> case CC_MINUS: >> if (z[1] =3D=3D '-') { >> - for (i =3D 2; (c =3D z[i]) !=3D 0 && c !=3D = '\n'; i++) { >> + for (i =3D 2; true; i++) { >> + if (z[i] =3D=3D '\0') { >> + *type =3D TK_SPACE; >=20 > 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 =3D 1 + sql_skip_spaces(z+1); *type =3D TK_SPACE; return i; + case CC_LINEFEED: + *type =3D 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] =3D=3D '-') { - for (i =3D 2; (c =3D z[i]) !=3D 0 && c !=3D = '\n'; i++) { + for (i =3D 2; true; i++) { + if (z[i] =3D=3D '\0') { + *type =3D TK_SPACE; + return i; + } else if (z[i] =3D=3D '\n') { + *type =3D TK_LINEFEED; + return ++i; + } } - *type =3D TK_SPACE; - return i; } *type =3D 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 + ]], { + -- + 2 + -- + }) =20 +test:do_catchsql_test( + "tokenize-3.2", + [[ + SELECT 1 + -- Syntax error. + * + ]], { + -- + 1,"Syntax error on line 2 at column 9 near '*'" + -- + }) >> 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 >>=20 >> for _, kw in ipairs(bannedkws) do >> query =3D 'CREATE TABLE '..kw..'(a INT PRIMARY KEY);' >> - test:do_catchsql_test( >> + if kw =3D=3D '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." >> }) >=20 > 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 =20 for _, kw in ipairs(bannedkws) do query =3D 'CREATE TABLE '..kw..'(a INT PRIMARY KEY);' - test:do_catchsql_test( + if kw =3D=3D 'end' or kw =3D=3D 'match' or kw =3D=3D 'release' or = kw =3D=3D 'rename' or + kw =3D=3D 'replace' or kw =3D=3D 'binary' or kw =3D=3D = 'character' or + kw =3D=3D '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 >>=20 >> - >> 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 =3D require("sqltester") >> -test:plan(58) >> +test:plan(59) >>=20 >> --!./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); >> + ]], { >> + -- >> + -- >=20 > Originally, these comments were generated automatically by tcl to Lua > converter. You don't have to put them to each test's result :) >=20 >> + }) >> + >> + 1, "Syntax error on line 1 at character 60 near ';'" >> -- >> }) >>=20 >> @@ -587,7 +587,7 @@ test:do_catchsql_test(6.9, [[ >> WITH x AS (SELECT * FROM t1) UPDATE t2 SET a =3D 10, b =3D 1 = WHERE a=3D=3D=3Db; >> ]], { >> -- <6.9> >> - 1, "Syntax error near '=3D'" >> + 1, "Syntax error on line 1 at character 71 near '=3D'" >> -- >> }) >>=20 >> 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 @@ _ =3D 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 ''<''' >=20 > 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 =3D true; } @@ -274,7 +285,12 @@ columnname(A) ::=3D nm(A) typedef(Y). = {sqlAddColumn(pParse,&A,&Y);} %type nm {Token} nm(A) ::=3D 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 =3D true; } } @@ -1072,15 +1088,25 @@ expr(A) ::=3D VARIABLE(X). { Token t =3D 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 =3D true; A.pExpr =3D NULL; } else if (!(X.z[0]=3D=3D'#' && sqlIsdigit(X.z[1]))) { u32 n =3D X.n; spanExpr(&A, pParse, TK_VARIABLE, X); if (A.pExpr->u.zToken[0] =3D=3D '?' && 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 =3D true; } else { sqlExprAssignVarNumber(pParse, A.pExpr, n); @@ -1088,7 +1114,12 @@ expr(A) ::=3D VARIABLE(X). { }else{ assert( t.n>=3D2 ); 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 =3D true; A.pExpr =3D NULL; } @@ -1604,8 +1635,9 @@ trigger_event(A) ::=3D UPDATE(X). {A.a =3D = @X; /*A-overwrites-X*/ A.b =3D 0;} trigger_event(A) ::=3D UPDATE OF idlist(X).{A.a =3D TK_UPDATE; A.b =3D = X;} =20 foreach_clause ::=3D . { - 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 =3D true; } foreach_clause ::=3D FOR EACH ROW. @@ -1635,8 +1667,9 @@ trigger_cmd_list(A) ::=3D trigger_cmd(A) SEMI. { trnm(A) ::=3D nm(A). trnm(A) ::=3D nm DOT nm(X). { A =3D 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 =3D true; } =20 @@ -1646,14 +1679,15 @@ trnm(A) ::=3D nm DOT nm(X). { // tridxby ::=3D . tridxby ::=3D 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 =3D true; } tridxby ::=3D 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 =3D 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 =3D=3D nil --- commit 747775f4c8ea531ee79e7befc311aa9c69411245 Author: Roman Khabibov Date: Sat Sep 28 20:16:45 2019 +0300 sql: print line and column number in error message =20 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. =20 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=3D" \ 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'") \ =20 /* * !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 =3D true; } @@ -274,7 +285,12 @@ columnname(A) ::=3D nm(A) typedef(Y). = {sqlAddColumn(pParse,&A,&Y);} %type nm {Token} nm(A) ::=3D 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 =3D true; } } @@ -1072,15 +1088,25 @@ expr(A) ::=3D VARIABLE(X). { Token t =3D 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 =3D true; A.pExpr =3D NULL; } else if (!(X.z[0]=3D=3D'#' && sqlIsdigit(X.z[1]))) { u32 n =3D X.n; spanExpr(&A, pParse, TK_VARIABLE, X); if (A.pExpr->u.zToken[0] =3D=3D '?' && 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 =3D true; } else { sqlExprAssignVarNumber(pParse, A.pExpr, n); @@ -1088,7 +1114,12 @@ expr(A) ::=3D VARIABLE(X). { }else{ assert( t.n>=3D2 ); 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 =3D true; A.pExpr =3D NULL; } @@ -1604,8 +1635,9 @@ trigger_event(A) ::=3D UPDATE(X). {A.a =3D = @X; /*A-overwrites-X*/ A.b =3D 0;} trigger_event(A) ::=3D UPDATE OF idlist(X).{A.a =3D TK_UPDATE; A.b =3D = X;} =20 foreach_clause ::=3D . { - 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 =3D true; } foreach_clause ::=3D FOR EACH ROW. @@ -1635,8 +1667,9 @@ trigger_cmd_list(A) ::=3D trigger_cmd(A) SEMI. { trnm(A) ::=3D nm(A). trnm(A) ::=3D nm DOT nm(X). { A =3D 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 =3D true; } =20 @@ -1646,14 +1679,15 @@ trnm(A) ::=3D nm DOT nm(X). { // tridxby ::=3D . tridxby ::=3D 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 =3D true; } tridxby ::=3D 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 =3D true; } =20 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 =3D db; parser->sql_flags =3D sql_flags; + parser->line_count =3D 1; + parser->line_pos =3D 1; region_create(&parser->region, &cord()->slabc); } =20 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 { = ***********************************************************************/ =20 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' */ =20 static const char sql_ascii_class[] =3D { /* 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 =3D 1 + sql_skip_spaces(z+1); *type =3D TK_SPACE; return i; + case CC_LINEFEED: + *type =3D 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] =3D=3D '-') { - for (i =3D 2; (c =3D z[i]) !=3D 0 && c !=3D = '\n'; i++) { + for (i =3D 2; true; i++) { + if (z[i] =3D=3D '\0') { + *type =3D TK_SPACE; + return i; + } else if (z[i] =3D=3D '\n') { + *type =3D TK_LINEFEED; + return ++i; + } } - *type =3D TK_SPACE; - return i; } *type =3D TK_MINUS; return 1; @@ -499,12 +512,26 @@ sqlRunParser(Parse * pParse, const char *zSql) assert(tokenType =3D=3D TK_SPACE || tokenType =3D=3D TK_ILLEGAL); if (tokenType =3D=3D 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 =3D true; break; } + } else if (tokenType =3D=3D TK_LINEFEED) { + pParse->line_count++; + pParse->line_pos =3D 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 +=3D pParse->sLastToken.n; } pParse->zTail =3D &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); ]], { -- - 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." -- }) =20 @@ -233,7 +233,7 @@ test:do_catchsql_test( ALTER TABLE child ADD CONSTRAINT fk () FOREIGN KEY REFERENCES = child(id); ]], { -- - 1, "Syntax error near '('" + 1, "Syntax error on line 1 at column 45 near '('" -- }) =20 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 ]], { -- - 1, [[Syntax error: unrecognized token: 'X'01020k304'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'X'01020k304'']] -- }) =20 @@ -81,7 +81,7 @@ test:do_catchsql_test( [[ SELECT X'01020, 100]], { -- - 1, [[Syntax error: unrecognized token: 'X'01020, 100']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'X'01020, 100']] -- }) =20 @@ -91,7 +91,7 @@ test:do_catchsql_test( SELECT X'01020 100' ]], { -- - 1, [[Syntax error: unrecognized token: 'X'01020 100'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'X'01020 100'']] -- }) =20 @@ -101,7 +101,7 @@ test:do_catchsql_test( SELECT X'01001' ]], { -- - 1, [[Syntax error: unrecognized token: 'X'01001'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'X'01001'']] -- }) =20 @@ -111,7 +111,7 @@ test:do_catchsql_test( SELECT x'012/45' ]], { -- - 1, [[Syntax error: unrecognized token: 'x'012/45'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'x'012/45'']] -- }) =20 @@ -121,7 +121,7 @@ test:do_catchsql_test( SELECT x'012:45' ]], { -- - 1, [[Syntax error: unrecognized token: 'x'012:45'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'x'012:45'']] -- }) =20 @@ -131,7 +131,7 @@ test:do_catchsql_test( SELECT x'012@45' ]], { -- - 1, [[Syntax error: unrecognized token: 'x'012@45'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'x'012@45'']] -- }) =20 @@ -141,7 +141,7 @@ test:do_catchsql_test( SELECT x'012G45' ]], { -- - 1, [[Syntax error: unrecognized token: 'x'012G45'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'x'012G45'']] -- }) =20 @@ -151,7 +151,7 @@ test:do_catchsql_test( SELECT x'012`45' ]], { -- - 1, [[Syntax error: unrecognized token: 'x'012`45'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'x'012`45'']] -- }) =20 @@ -161,7 +161,7 @@ test:do_catchsql_test( SELECT x'012g45' ]], { -- - 1, [[Syntax error: unrecognized token: 'x'012g45'']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = 'x'012g45'']] -- }) =20 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( ); ]], { -- - 1,"Syntax error near ','" + 1,"Syntax error on line 2 at column 77 near ','" -- }) =20 @@ -296,7 +296,7 @@ test:do_catchsql_test( ); ]], { -- - 1,"Syntax error near ','" + 1,"Syntax error on line 3 at column 23 near ','" -- }) =20 @@ -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." -- }) =20 @@ -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." -- }) =20 @@ -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." -- }) =20 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 ]], { -- - 1, [[Syntax error near '*']] + 1, [[Syntax error on line 1 at column 31 near '*']] -- }) =20 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); ]], { -- - 1, "Syntax error near 'id'" + 1, "Syntax error on line 1 at column 64 near 'id'" -- }) =20 @@ -234,7 +234,7 @@ test:do_catchsql_test( CREATE TABLE t6(id INTEGER PRIMARY KEY, b TEXT DEFAULT "id"); ]], { -- - 1, "Syntax error near '\"id\"'" + 1, "Syntax error on line 1 at column 64 near '\"id\"'" -- }) =20 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=3Dt2.a) ]], { -- - 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.]] -- }) =20 @@ -805,9 +805,9 @@ test:do_select_tests( -- FROM clause. -- data =3D { - {"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) ]], { -- - 1, "Syntax error near ','" + 1, "Syntax error on line 1 at column 22 near ','" -- }) =20 @@ -2228,7 +2228,7 @@ test:do_catchsql_test( SELECT TRIM(FROM 'xyxzy'); ]], { -- - 1, "Syntax error near 'FROM'" + 1, "Syntax error on line 1 at column 21 near 'FROM'" -- }) =20 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 =3D require("sqltester") -test:plan(2) +test:plan(3) =20 test:do_catchsql_test( "trigger2-10.1", @@ -8,23 +8,32 @@ test:do_catchsql_test( CREATE TEMP TABLE tmp1 (id INTEGER PRIMARY KEY); ]], { -- - 1, "Syntax error near 'TEMP'" + 1, "Syntax error on line 1 at column 10 near 'TEMP'" -- }); =20 -- 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); + ]], { + -- + -- +}); + +test:do_catchsql_test( + "trigger2-10.3", + [[ CREATE TEMP TRIGGER ttmp1 BEFORE UPDATE ON t1 BEGIN SELECT 1; END; ]], { - -- - 1, "Syntax error near 'TEMP'" - -- + -- + 1, "Syntax error on line 1 at column 10 near 'TEMP'" + -- }); =20 =20 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 =3D { { 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 =3D t1.a;", { - 1, "Syntax error near '.'", + 1, "Syntax error on line 1 at column 23 near '.'", }) =20 -- 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); ]], { -- - 1, "Syntax error near '.'" + 1, "Syntax error on line 1 at column 26 near '.'" -- }) =20 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 =3D require("sqltester") -test:plan(11) +test:plan(12) =20 --!./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 =3D 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." }) =20 -- 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 =20 for _, kw in ipairs(bannedkws) do query =3D 'CREATE TABLE '..kw..'(a INT PRIMARY KEY);' - test:do_catchsql_test( + if kw =3D=3D 'end' or kw =3D=3D 'match' or kw =3D=3D 'release' or = kw =3D=3D 'rename' or + kw =3D=3D 'replace' or kw =3D=3D 'binary' or kw =3D=3D = 'character' or + kw =3D=3D '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 =20 =20 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 =3D require("sqltester") -test:plan(58) +test:plan(59) =20 --!./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); + ]], { + -- + -- + }) + +test:do_catchsql_test( + "misc1-5.1.2", + [[ UPDATE t3 SET a=3D0 WHEREwww b=3D2; ]], { - -- - 1, [[Syntax error near 'WHEREwww']] - -- + -- + 1, [[Syntax error on line 1 at column 27 near 'WHEREwww']] + -- }) =20 test:do_execsql_test( @@ -1037,7 +1046,7 @@ test:do_catchsql_test( select''like''like''like#0; ]], { -- - 1, [[Syntax error near '#0']] + 1, [[Syntax error on line 1 at column 35 near '#0']] -- }) =20 @@ -1047,7 +1056,7 @@ test:do_catchsql_test( VALUES(0,0x0MATCH#0; ]], { -- - 1, [[Syntax error near '#0']] + 1, [[Syntax error on line 1 at column 28 near '#0']] -- }) =20 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 ]], { -- - 1, [[Syntax error: unrecognized token: '123abc']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '123abc']] -- }) =20 @@ -357,7 +357,7 @@ test:do_catchsql_test( SELECT 1*123.4e5ghi; ]], { -- - 1, [[Syntax error: unrecognized token: '123.4e5ghi']] + 1, [[Syntax error on line 1 at column 18 unrecognized token: = '123.4e5ghi']] -- }) =20 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( ]], { -- - 1, "Syntax error near '1'" + 1, "Syntax error on line 1 at column 29 near '1'" -- }) =20 @@ -528,7 +528,7 @@ test:do_catchsql_test( ]], { -- - 1, "Syntax error near '1'" + 1, "Syntax error on line 1 at column 33 near '1'" -- }) =20 @@ -539,7 +539,7 @@ test:do_catchsql_test( ]], { -- - 1, "Syntax error near '1'" + 1, "Syntax error on line 1 at column 32 near '1'" -- }) =20 @@ -550,7 +550,7 @@ test:do_catchsql_test( ]], { -- - 1, "Syntax error near '1'" + 1, "Syntax error on line 1 at column 36 near '1'" -- }) =20 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''" }) =20 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'" }) =20 -- 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=3D; ]], { -- - 1, [[Syntax error near ';']] + 1, [[Syntax error on line 1 at column 39 near ';']] -- }) =20 @@ -1416,7 +1416,7 @@ test:do_catchsql_test( SELECT f1 FROM test1 UNION SELECT WHERE; ]], { -- - 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.]] -- }) =20 @@ -1428,7 +1428,7 @@ test:do_catchsql_test( [[ SELECT f1 FROM test1 as "hi", test2 as]], { -- - 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.]] -- }) =20 @@ -1438,7 +1438,7 @@ test:do_catchsql_test( SELECT f1 FROM test1 ORDER BY; ]], { -- - 1, [[Syntax error near ';']] + 1, [[Syntax error on line 1 at column 38 near ';']] -- }) =20 @@ -1448,7 +1448,7 @@ test:do_catchsql_test( SELECT f1 FROM test1 ORDER BY f1 desc, f2 where; ]], { -- - 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.]] -- }) =20 @@ -1458,7 +1458,7 @@ test:do_catchsql_test( SELECT count(f1,f2 FROM test1; ]], { -- - 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.]] -- }) =20 @@ -1468,7 +1468,7 @@ test:do_catchsql_test( SELECT count(f1,f2+) FROM test1; ]], { -- - 1, [[Syntax error near ')']] + 1, [[Syntax error on line 1 at column 28 near ')']] -- }) =20 @@ -1478,7 +1478,7 @@ test:do_catchsql_test( SELECT f1 FROM test1 ORDER BY f2, f1+; ]], { -- - 1, [[Syntax error near ';']] + 1, [[Syntax error on line 1 at column 46 near ';']] -- }) =20 @@ -1488,7 +1488,7 @@ test:do_catchsql_test( SELECT f1 FROM test1 LIMIT 5+3 OFFSET 11 ORDER BY f2; ]], { -- - 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.]] -- }) =20 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; ]], { -- - 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.]] -- }) =20 @@ -190,7 +190,7 @@ test:do_catchsql_test("select3-2.14", [[ SELECT log, count(*) FROM t1 GROUP BY; ]], { -- - 1, [[Syntax error near ';']] + 1, [[Syntax error on line 1 at column 40 near ';']] -- }) =20 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; ]], { -- - 1,"Syntax error near 'ANALYZE'" + 1,"Syntax error on line 1 at column 3 near 'ANALYZE'" -- }) =20 @@ -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; ]], { -- - 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" -- }) =20 @@ -522,7 +522,7 @@ test:do_catchsql_test( DROP TABLE IF EXISTS END; ]], { -- - 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." -- }) =20 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; ]], { -- - 1, "Syntax error near 'BEGIN'" + 1, "Syntax error on line 2 at column 3 near 'BEGIN'" -- }) =20 @@ -46,7 +46,7 @@ test:do_catchsql_test( COMMIT; ]], { -- - 1, "Syntax error near 'BEGIN'" + 1, "Syntax error on line 2 at column 3 near 'BEGIN'" -- }) =20 @@ -94,7 +94,7 @@ test:do_catchsql_test( COMMIT TRANSACTION; ]], { -- - 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." -- }) =20 @@ -119,7 +119,7 @@ test:do_catchsql_test( END; ]], { -- - 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." -- }) =20 @@ -144,7 +144,7 @@ test:do_catchsql_test( END TRANSACTION; ]], { -- - 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." -- }) =20 @@ -193,7 +193,7 @@ test:do_catchsql_test( COMMIT; ]], { -- - 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." -- }) =20 @@ -246,7 +246,7 @@ test:do_catchsql_test( COMMIT; ]], { -- - 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." -- }) =20 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)); ]], { -- - 1, "Syntax error near 'TEMP'" + 1, "Syntax error on line 1 at column 10 near 'TEMP'" -- }) =20 @@ -630,7 +630,7 @@ test:do_catchsql_test( CREATE TEMPORARY TABLE t1(a INTEGER PRIMARY KEY, b = VARCHAR(10)); ]], { -- - 1, "Syntax error near 'TEMPORARY'" + 1, "Syntax error on line 1 at column 10 near 'TEMPORARY'" -- }) =20 @@ -1257,7 +1257,7 @@ test:do_catchsql_test( ); ]], { -- - 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." -- }) =20 @@ -1322,7 +1322,7 @@ test:do_catchsql_test( ); ]], { -- - 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." -- }) =20 @@ -1336,7 +1336,7 @@ test:do_catchsql_test( ); ]], { -- - 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." -- }) =20 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 =3D require("sqltester") -test:plan(14) +test:plan(16) =20 --!./tcltestrunner.lua -- 2008 July 7 @@ -26,7 +26,7 @@ test:do_catchsql_test( SELECT 1.0e+ ]], { -- - 1, [[Syntax error: unrecognized token: '1.0e']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0e']] -- }) =20 @@ -36,7 +36,7 @@ test:do_catchsql_test( SELECT 1.0E+ ]], { -- - 1, [[Syntax error: unrecognized token: '1.0E']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0E']] -- }) =20 @@ -46,7 +46,7 @@ test:do_catchsql_test( SELECT 1.0e- ]], { -- - 1, [[Syntax error: unrecognized token: '1.0e']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0e']] -- }) =20 @@ -56,7 +56,7 @@ test:do_catchsql_test( SELECT 1.0E- ]], { -- - 1, [[Syntax error: unrecognized token: '1.0E']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0E']] -- }) =20 @@ -66,7 +66,7 @@ test:do_catchsql_test( SELECT 1.0e+/ ]], { -- - 1, [[Syntax error: unrecognized token: '1.0e']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0e']] -- }) =20 @@ -76,7 +76,7 @@ test:do_catchsql_test( SELECT 1.0E+: ]], { -- - 1, [[Syntax error: unrecognized token: '1.0E']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0E']] -- }) =20 @@ -86,7 +86,7 @@ test:do_catchsql_test( SELECT 1.0e-: ]], { -- - 1, [[Syntax error: unrecognized token: '1.0e']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0e']] -- }) =20 @@ -96,7 +96,7 @@ test:do_catchsql_test( SELECT 1.0E-/ ]], { -- - 1, [[Syntax error: unrecognized token: '1.0E']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0E']] -- }) =20 @@ -106,7 +106,7 @@ test:do_catchsql_test( SELECT 1.0F+5 ]], { -- - 1, [[Syntax error: unrecognized token: '1.0F']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0F']] -- }) =20 @@ -116,7 +116,7 @@ test:do_catchsql_test( SELECT 1.0d-10 ]], { -- - 1, [[Syntax error: unrecognized token: '1.0d']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0d']] -- }) =20 @@ -126,7 +126,7 @@ test:do_catchsql_test( SELECT 1.0e,5 ]], { -- - 1, [[Syntax error: unrecognized token: '1.0e']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0e']] -- }) =20 @@ -136,7 +136,7 @@ test:do_catchsql_test( SELECT 1.0E.10 ]], { -- - 1, [[Syntax error: unrecognized token: '1.0E']] + 1, [[Syntax error on line 1 at column 16 unrecognized token: = '1.0E']] -- }) =20 @@ -145,7 +145,7 @@ test:do_catchsql_test( [[ SELECT 1, 2 /*]], { -- - 1, [[Syntax error near '*']] + 1, [[Syntax error on line 1 at column 22 near '*']] -- }) =20 @@ -159,6 +159,29 @@ test:do_catchsql_test( -- }) =20 +-- +--gh-2611 Check the correct parsing of single-line comments. +-- +test:do_execsql_test( + "tokenize-3.1", + [[ + SELECT 1 + -- 1 + 1. + 1 + ]], { + -- + 2 + -- + }) =20 +test:do_catchsql_test( + "tokenize-3.2", + [[ + SELECT 1 + -- Syntax error. + * + ]], { + -- + 1,"Syntax error on line 2 at column 9 near '*'" + -- + }) =20 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; ]], { -- - 1, [[Syntax error near 'STATEMENT']] + 1, [[Syntax error on line 1 at column 51 near 'STATEMENT']] -- }) =20 @@ -307,7 +307,7 @@ test:do_catchsql_test( END; ]], { -- - 1, [[Syntax error near ';']] + 1, [[Syntax error on line 3 at column 24 near ';']] -- }) =20 @@ -321,7 +321,7 @@ test:do_catchsql_test( END; ]], { -- - 1, [[Syntax error near ';']] + 1, [[Syntax error on line 4 at column 24 near ';']] -- }) =20 @@ -823,7 +823,7 @@ test:do_catchsql_test( END; ]], { -- - 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" -- }) =20 @@ -835,7 +835,7 @@ test:do_catchsql_test( END; ]], { -- - 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" -- }) =20 @@ -847,7 +847,7 @@ test:do_catchsql_test( END; ]], { -- - 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" -- }) =20 @@ -859,7 +859,7 @@ test:do_catchsql_test( END; ]], { -- - 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" -- }) =20 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; ]], { -- - 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.]] -- }) =20 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.]] -- }) =20 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 ')']] -- }) =20 @@ -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 ')']] -- }) =20 @@ -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.]] -- }) =20 @@ -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.]] -- }) =20 @@ -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 ';']] -- }) =20 @@ -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'" -- }) =20 @@ -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'" -- }) =20 @@ -579,7 +579,7 @@ test:do_catchsql_test(6.8, [[ WITH x AS (SELECT * FROM t1) UPDATE t2 SET a =3D 10, b =3D ; ]], { -- <6.8> - 1, "Syntax error near ';'" + 1, "Syntax error on line 1 at column 60 near ';'" -- }) =20 @@ -587,7 +587,7 @@ test:do_catchsql_test(6.9, [[ WITH x AS (SELECT * FROM t1) UPDATE t2 SET a =3D 10, b =3D 1 WHERE = a=3D=3D=3Db; ]], { -- <6.9> - 1, "Syntax error near '=3D'" + 1, "Syntax error on line 1 at column 71 near '=3D'" -- }) =20 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 =3D=3D 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 @@ _ =3D box.space.test:create_index('pk') =20 -- 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 =3D = 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 =3D = 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 =3D = 'VINYL'") --- @@ -119,7 +119,7 @@ box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY = KEY) WITH ENGINE =3D 'VINYL'") box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE =3D = \"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=3D\''..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 =3D 5;') @@ -119,7 +119,7 @@ cn:execute('select id as identifier from test where = a =3D 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 =3D 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 =3D=3D 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=3D\''..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 =3D 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 =3D 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. --