diff --git a/CHANGELOG b/CHANGELOG index 35465f0d75..0a6e3e5872 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,16 @@ v3.4.9 (XXX-XX-XX) ------------------- +* Properly report parse errors for extraneous unterminated string literals + at the end of AQL query strings. For example, in the query `RETURN 1 "abc`, + the `RETURN 1` part was parsed fully, and the `"abc` part at the end was + parsed until the EOF and then forgotten. But as the fully parsed tokens + `RETURN 1` already form a proper query, the unterminated string literal + at the end was not reported as a parse error. + This is now fixed for unterminated string literals in double and single + quotes as well as unterminated multi-line comments at the end of the query + string. + * Fixed issue #10078: FULLTEXT with sort on same field not working. * Fixed issue #10062: AQL: Could not extract custom attribute. diff --git a/arangod/Aql/tokens.cpp b/arangod/Aql/tokens.cpp index c3e17bf8ef..080bdf0e0b 100644 --- a/arangod/Aql/tokens.cpp +++ b/arangod/Aql/tokens.cpp @@ -2021,6 +2021,12 @@ YY_RULE_SETUP /* newline character inside backtick */ } YY_BREAK +case YY_STATE_EOF(BACKTICK): +{ + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated identifier", yylloc->first_line, yylloc->first_column); +} + YY_BREAK case 67: YY_RULE_SETUP { @@ -2059,6 +2065,12 @@ YY_RULE_SETUP /* newline character inside forwardtick */ } YY_BREAK +case YY_STATE_EOF(FORWARDTICK): +{ + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated identifier", yylloc->first_line, yylloc->first_column); +} + YY_BREAK case 72: YY_RULE_SETUP { @@ -2099,6 +2111,12 @@ YY_RULE_SETUP /* newline character inside quote */ } YY_BREAK +case YY_STATE_EOF(DOUBLE_QUOTE): +{ + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated string literal", yylloc->first_line, yylloc->first_column); +} + YY_BREAK case 77: YY_RULE_SETUP { @@ -2136,6 +2154,12 @@ YY_RULE_SETUP /* newline character inside quote */ } YY_BREAK +case YY_STATE_EOF(SINGLE_QUOTE): +{ + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated string literal", yylloc->first_line, yylloc->first_column); +} + YY_BREAK case 82: YY_RULE_SETUP { @@ -2287,6 +2311,12 @@ YY_RULE_SETUP // eat the lone star } YY_BREAK +case YY_STATE_EOF(COMMENT_MULTI): +{ + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated multi-line comment", yylloc->first_line, yylloc->first_column); +} + YY_BREAK case 96: /* rule 96 can match eol */ YY_RULE_SETUP @@ -2344,12 +2374,7 @@ YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(BACKTICK): -case YY_STATE_EOF(FORWARDTICK): -case YY_STATE_EOF(SINGLE_QUOTE): -case YY_STATE_EOF(DOUBLE_QUOTE): case YY_STATE_EOF(COMMENT_SINGLE): -case YY_STATE_EOF(COMMENT_MULTI): yyterminate(); case YY_END_OF_BUFFER: diff --git a/arangod/Aql/tokens.ll b/arangod/Aql/tokens.ll index c6ad2440f5..63ed20b70a 100644 --- a/arangod/Aql/tokens.ll +++ b/arangod/Aql/tokens.ll @@ -356,6 +356,11 @@ class Parser; /* newline character inside backtick */ } +<> { + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated identifier", yylloc->first_line, yylloc->first_column); +} + . { /* any character (except newline) inside backtick */ } @@ -384,6 +389,11 @@ class Parser; /* newline character inside forwardtick */ } +<> { + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated identifier", yylloc->first_line, yylloc->first_column); +} + . { /* any character (except newline) inside forwardtick */ } @@ -414,6 +424,11 @@ class Parser; /* newline character inside quote */ } +<> { + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated string literal", yylloc->first_line, yylloc->first_column); +} + . { /* any character (except newline) inside quote */ } @@ -440,6 +455,11 @@ class Parser; /* newline character inside quote */ } +<> { + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated string literal", yylloc->first_line, yylloc->first_column); +} + . { /* any character (except newline) inside quote */ } @@ -566,6 +586,11 @@ class Parser; // eat the lone star } +<> { + auto parser = yyextra; + parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected unterminated multi-line comment", yylloc->first_line, yylloc->first_column); +} + \n { /* line numbers are counted elsewhere already */ yycolumn = 0; diff --git a/tests/js/server/aql/aql-parse.js b/tests/js/server/aql/aql-parse.js index 4a6add2dfd..4e361c39a5 100644 --- a/tests/js/server/aql/aql-parse.js +++ b/tests/js/server/aql/aql-parse.js @@ -119,6 +119,17 @@ function ahuacatlParseTestSuite () { assertParseError(errors.ERROR_QUERY_PARSE.code, "return 1 + 1 +"); assertParseError(errors.ERROR_QUERY_PARSE.code, "return (1"); assertParseError(errors.ERROR_QUERY_PARSE.code, "for f1 in x1"); + assertParseError(errors.ERROR_QUERY_PARSE.code, "return 00"); + assertParseError(errors.ERROR_QUERY_PARSE.code, "return 01"); + assertParseError(errors.ERROR_QUERY_PARSE.code, "return 1."); + assertParseError(errors.ERROR_QUERY_PARSE.code, "return -"); + assertParseError(errors.ERROR_QUERY_PARSE.code, "return +"); + assertParseError(errors.ERROR_QUERY_PARSE.code, "return ."); + assertParseError(errors.ERROR_QUERY_PARSE.code, "RETURN 1 /* "); + assertParseError(errors.ERROR_QUERY_PARSE.code, "RETURN 1 \" foo "); + assertParseError(errors.ERROR_QUERY_PARSE.code, "RETURN 1 ' foo "); + assertParseError(errors.ERROR_QUERY_PARSE.code, "RETURN 1 `foo "); + assertParseError(errors.ERROR_QUERY_PARSE.code, "RETURN 1 ´foo "); }, ////////////////////////////////////////////////////////////////////////////////