2015-04-11 03:10:23 +00:00
|
|
|
#include <DB/Parsers/parseQuery.h>
|
2016-10-24 18:18:43 +00:00
|
|
|
#include <DB/Parsers/ParserQuery.h>
|
|
|
|
#include <DB/Parsers/ASTInsertQuery.h>
|
|
|
|
#include <DB/Common/StringUtils.h>
|
2015-04-11 03:10:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int SYNTAX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
/** From position in (possible multiline) query, get line number and column number in line.
|
|
|
|
* Used in syntax error message.
|
2015-04-11 03:10:23 +00:00
|
|
|
*/
|
2016-01-11 21:46:36 +00:00
|
|
|
static std::pair<size_t, size_t> getLineAndCol(IParser::Pos begin, IParser::Pos pos)
|
2015-04-11 03:10:23 +00:00
|
|
|
{
|
|
|
|
size_t line = 0;
|
|
|
|
|
|
|
|
IParser::Pos nl;
|
|
|
|
while (nullptr != (nl = reinterpret_cast<IParser::Pos>(memchr(begin, '\n', pos - begin))))
|
|
|
|
{
|
|
|
|
++line;
|
|
|
|
begin = nl + 1;
|
|
|
|
}
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
/// Lines numbered from 1.
|
2015-04-11 03:10:23 +00:00
|
|
|
return { line + 1, pos - begin + 1 };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static std::string getSyntaxErrorMessage(
|
|
|
|
IParser::Pos begin,
|
|
|
|
IParser::Pos end,
|
|
|
|
IParser::Pos max_parsed_pos,
|
|
|
|
Expected expected,
|
2015-04-11 04:15:14 +00:00
|
|
|
bool hilite,
|
2015-04-11 03:10:23 +00:00
|
|
|
const std::string & description)
|
|
|
|
{
|
|
|
|
std::stringstream message;
|
|
|
|
|
|
|
|
message << "Syntax error";
|
|
|
|
|
|
|
|
if (!description.empty())
|
|
|
|
message << " (" << description << ")";
|
|
|
|
|
2015-04-11 04:15:14 +00:00
|
|
|
if (max_parsed_pos == end || *max_parsed_pos == ';')
|
2015-04-11 03:10:23 +00:00
|
|
|
{
|
2015-04-14 01:39:30 +00:00
|
|
|
message << ": failed at end of query.\n";
|
|
|
|
|
|
|
|
if (expected && *expected && *expected != '.')
|
|
|
|
message << "Expected " << expected;
|
2015-04-11 04:15:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
message << ": failed at position " << (max_parsed_pos - begin + 1);
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
/// If query is multiline.
|
2015-04-11 04:15:14 +00:00
|
|
|
IParser::Pos nl = reinterpret_cast<IParser::Pos>(memchr(begin, '\n', end - begin));
|
|
|
|
if (nullptr != nl && nl + 1 != end)
|
|
|
|
{
|
|
|
|
size_t line = 0;
|
|
|
|
size_t col = 0;
|
|
|
|
std::tie(line, col) = getLineAndCol(begin, max_parsed_pos);
|
|
|
|
|
|
|
|
message << " (line " << line << ", col " << col << ")";
|
|
|
|
}
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
/// Hilite place of syntax error.
|
2015-04-11 04:15:14 +00:00
|
|
|
if (hilite)
|
|
|
|
{
|
|
|
|
message << ":\n\n";
|
|
|
|
message.write(begin, max_parsed_pos - begin);
|
2015-06-06 19:59:16 +00:00
|
|
|
|
|
|
|
size_t bytes_to_hilite = 1;
|
|
|
|
while (max_parsed_pos + bytes_to_hilite < end
|
|
|
|
&& static_cast<unsigned char>(max_parsed_pos[bytes_to_hilite]) >= 0x80 /// UTF-8
|
|
|
|
&& static_cast<unsigned char>(max_parsed_pos[bytes_to_hilite]) <= 0xBF)
|
|
|
|
++bytes_to_hilite;
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
message << "\033[41;1m" << std::string(max_parsed_pos, bytes_to_hilite) << "\033[0m"; /// Bright red background.
|
2015-06-06 19:59:16 +00:00
|
|
|
message.write(max_parsed_pos + bytes_to_hilite, end - max_parsed_pos - bytes_to_hilite);
|
2015-04-11 04:15:14 +00:00
|
|
|
message << "\n\n";
|
|
|
|
|
|
|
|
if (expected && *expected && *expected != '.')
|
|
|
|
message << "Expected " << expected;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
message << ": " << std::string(max_parsed_pos, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, end - max_parsed_pos));
|
|
|
|
|
|
|
|
if (expected && *expected && *expected != '.')
|
|
|
|
message << ", expected " << expected;
|
|
|
|
}
|
2015-04-11 03:10:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return message.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-11 04:15:14 +00:00
|
|
|
ASTPtr tryParseQuery(
|
|
|
|
IParser & parser,
|
2015-04-14 20:46:34 +00:00
|
|
|
IParser::Pos & pos,
|
2015-04-11 04:15:14 +00:00
|
|
|
IParser::Pos end,
|
|
|
|
std::string & out_error_message,
|
|
|
|
bool hilite,
|
2016-08-17 05:38:51 +00:00
|
|
|
const std::string & description,
|
|
|
|
bool allow_multi_statements)
|
2015-04-11 03:10:23 +00:00
|
|
|
{
|
2015-04-14 20:46:34 +00:00
|
|
|
if (pos == end || *pos == ';')
|
2015-04-11 03:10:23 +00:00
|
|
|
{
|
|
|
|
out_error_message = "Empty query";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected expected = "";
|
2015-04-14 20:46:34 +00:00
|
|
|
IParser::Pos begin = pos;
|
2015-04-11 03:10:23 +00:00
|
|
|
IParser::Pos max_parsed_pos = pos;
|
|
|
|
|
|
|
|
ASTPtr res;
|
|
|
|
bool parse_res = parser.parse(pos, end, res, max_parsed_pos, expected);
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
/// Parsed query must end with end of data or semicolon.
|
2015-04-11 03:10:23 +00:00
|
|
|
if (!parse_res || (pos != end && *pos != ';'))
|
|
|
|
{
|
2015-04-11 04:15:14 +00:00
|
|
|
out_error_message = getSyntaxErrorMessage(begin, end, max_parsed_pos, expected, hilite, description);
|
2015-04-11 03:10:23 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-08-17 05:38:51 +00:00
|
|
|
/// If multi-statements are not allowed, then after semicolon, there must be no non-space characters.
|
|
|
|
if (!allow_multi_statements && pos < end && *pos == ';')
|
|
|
|
{
|
|
|
|
++pos;
|
|
|
|
while (pos < end && isWhitespaceASCII(*pos))
|
|
|
|
++pos;
|
|
|
|
|
|
|
|
if (pos < end)
|
|
|
|
{
|
|
|
|
out_error_message = getSyntaxErrorMessage(begin, end, pos, nullptr, hilite,
|
|
|
|
(description.empty() ? std::string() : std::string(". ")) + "Multi-statements are not allowed");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-11 03:10:23 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-14 20:46:34 +00:00
|
|
|
ASTPtr parseQueryAndMovePosition(
|
2015-04-11 04:15:14 +00:00
|
|
|
IParser & parser,
|
2015-04-14 20:46:34 +00:00
|
|
|
IParser::Pos & pos,
|
2015-04-11 04:15:14 +00:00
|
|
|
IParser::Pos end,
|
2016-08-17 05:38:51 +00:00
|
|
|
const std::string & description,
|
|
|
|
bool allow_multi_statements)
|
2015-04-11 03:10:23 +00:00
|
|
|
{
|
|
|
|
std::string error_message;
|
2016-08-17 05:38:51 +00:00
|
|
|
ASTPtr res = tryParseQuery(parser, pos, end, error_message, false, description, allow_multi_statements);
|
2015-04-11 03:10:23 +00:00
|
|
|
|
|
|
|
if (res)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
throw Exception(error_message, ErrorCodes::SYNTAX_ERROR);
|
|
|
|
}
|
|
|
|
|
2015-04-14 20:46:34 +00:00
|
|
|
|
|
|
|
ASTPtr parseQuery(
|
|
|
|
IParser & parser,
|
|
|
|
IParser::Pos begin,
|
|
|
|
IParser::Pos end,
|
|
|
|
const std::string & description)
|
|
|
|
{
|
|
|
|
auto pos = begin;
|
2016-08-17 05:38:51 +00:00
|
|
|
return parseQueryAndMovePosition(parser, pos, end, description, false);
|
2015-04-14 20:46:34 +00:00
|
|
|
}
|
|
|
|
|
2016-10-25 12:14:27 +00:00
|
|
|
std::pair<const char *, bool> splitMultipartQuery(const std::string & queries, std::vector<std::string> & queries_list)
|
2016-10-24 18:18:43 +00:00
|
|
|
{
|
|
|
|
ASTPtr ast;
|
|
|
|
ParserQuery parser;
|
|
|
|
|
2016-10-31 14:31:26 +00:00
|
|
|
const char * begin = queries.data(); /// begin of current query
|
|
|
|
const char * pos = begin; /// parser moves pos from begin to the end of current query
|
2016-10-24 18:18:43 +00:00
|
|
|
const char * end = begin + queries.size();
|
|
|
|
|
|
|
|
queries_list.clear();
|
|
|
|
|
2016-10-31 14:31:26 +00:00
|
|
|
while (pos < end)
|
2016-10-24 18:18:43 +00:00
|
|
|
{
|
2016-10-31 14:31:26 +00:00
|
|
|
begin = pos;
|
2016-10-24 18:18:43 +00:00
|
|
|
|
|
|
|
ast = parseQueryAndMovePosition(parser, pos, end, "", true);
|
|
|
|
if (!ast)
|
2016-10-25 13:49:07 +00:00
|
|
|
break;
|
2016-10-24 18:18:43 +00:00
|
|
|
|
2016-11-11 17:01:02 +00:00
|
|
|
ASTInsertQuery * insert = typeid_cast<ASTInsertQuery *>(ast.get());
|
2016-10-24 18:18:43 +00:00
|
|
|
|
|
|
|
if (insert && insert->data)
|
|
|
|
{
|
2016-11-11 17:01:02 +00:00
|
|
|
/// Inserting data is broken on new line
|
2016-10-24 18:18:43 +00:00
|
|
|
pos = insert->data;
|
|
|
|
while (*pos && *pos != '\n')
|
|
|
|
++pos;
|
|
|
|
insert->end = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
queries_list.emplace_back(queries.substr(begin - queries.data(), pos - begin));
|
|
|
|
|
2016-10-31 14:31:26 +00:00
|
|
|
while (isWhitespaceASCII(*pos) || *pos == ';')
|
|
|
|
++pos;
|
2016-10-24 18:18:43 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 14:31:26 +00:00
|
|
|
return std::make_pair(begin, pos == end);
|
2016-10-24 18:18:43 +00:00
|
|
|
}
|
|
|
|
|
2015-04-11 03:10:23 +00:00
|
|
|
}
|