Skip to content

Commit

Permalink
add execute queries by ast
Browse files Browse the repository at this point in the history
  • Loading branch information
nooblose committed May 24, 2024
1 parent 08d895e commit ea7579e
Show file tree
Hide file tree
Showing 7 changed files with 1,706 additions and 36 deletions.
1,452 changes: 1,422 additions & 30 deletions src/Interpreters/executeQuery.cpp

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions src/Interpreters/executeQuery.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "Parsers/IAST_fwd.h"
#include <Core/QueryProcessingStage.h>
#include <Formats/FormatSettings.h>
#include <Interpreters/Context_fwd.h>
Expand Down Expand Up @@ -35,6 +36,19 @@ struct QueryFlags
bool distributed_backup_restore = false; /// If true, this query is a part of backup restore.
};

struct QueryData
{
ASTPtr ast;
std::unique_ptr<ReadBuffer> istr;
std::string query;
std::string query_for_logging;
};

QueryData getQueryData(
ReadBuffer & istr,
ContextMutablePtr context,
QueryFlags flags = {},
const QueryProcessingStage::Enum stage = QueryProcessingStage::Enum::Complete);

/// Parse and execute a query.
void executeQuery(
Expand All @@ -48,6 +62,15 @@ void executeQuery(
HandleExceptionInOutputFormatFunc handle_exception_in_output_format = {} /// If a non-empty callback is passed, it will be called on exception with created output format.
);

void executeQuery(
QueryData & query_data,
WriteBuffer & ostr,
bool allow_into_outfile,
ContextMutablePtr context,
SetResultDetailsFunc set_result_details,
QueryFlags flags = {},
const std::optional<FormatSettings> & output_format_settings = std::nullopt,
HandleExceptionInOutputFormatFunc handle_exception_in_output_format = {});

/// More low-level function for server-to-server interaction.
/// Prepares a query for execution but doesn't execute it.
Expand Down
104 changes: 104 additions & 0 deletions src/Server/HTTP/HTTPQueryAST.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "HTTPQueryAST.h"

#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/IAST.h>
#include <Parsers/IParser.h>
#include <Parsers/TokenIterator.h>

namespace DB
{

namespace
{

static constexpr auto kColumns = "columns";
static constexpr auto kSelect = "select";
static constexpr auto kWhere = "where";
static constexpr auto kOrder = "order";

template <typename T>
ASTPtr parseExpression(const std::string & expression, const std::optional<ParserKeyword> & keyword = std::nullopt)
{
ASTPtr ast;
Tokens tokens(expression.c_str(), expression.c_str() + expression.size());
IParser::Pos pos(tokens, 0, 0);
Expected expected;

ParserKeyword s_select(Keyword::SELECT);

if (keyword.has_value())
s_select.ignore(pos, expected);

T(false).parse(pos, ast, expected);
return ast;
}

ASTPtr parseSelect(const std::string & select)
{
ParserKeyword s_select(Keyword::SELECT);

ASTPtr result;
Tokens tokens(select.c_str(), select.c_str() + select.size());
IParser::Pos pos(tokens, 0, 0);
Expected expected;

s_select.ignore(pos, expected);

ParserNotEmptyExpressionList(false).parse(pos, result, expected);
return result;
}

ASTPtr parseColumns(const std::string & columns)
{
ASTPtr result;
Tokens tokens(columns.c_str(), columns.c_str() + columns.size());
IParser::Pos pos(tokens, 0, 0);
Expected expected;

ParserNotEmptyExpressionList(false).parse(pos, result, expected);
return result;
}

ASTPtr parseWhere(const std::string & where)
{
ASTPtr result;
Tokens tokens(where.c_str(), where.c_str() + where.size());
IParser::Pos pos(tokens, 0, 0);
Expected expected;

ParserExpressionWithOptionalAlias(false).parse(pos, result, expected);
return result;
}

ASTPtr parseOrder(const std::string & order)
{
ASTPtr result;
Tokens tokens(order.c_str(), order.c_str() + order.size());
IParser::Pos pos(tokens, 0, 0);
Expected expected;

ParserOrderByExpressionList().parse(pos, result, expected);
return result;
}

}

HTTPQueryAST getHTTPQueryAST(HTMLForm & params)
{
HTTPQueryAST result;

for (const auto & [key, value] : params)
if (key == kColumns)
result.select_expressions.push_back(parseColumns(value));
else if (key == kSelect)
result.select_expressions.push_back(parseSelect(value));
else if (key == kWhere)
result.where_expressions.push_back(parseWhere(value));
else if (key == kOrder)
result.order_expressions.push_back(parseOrder(value));

return result;
}

}
20 changes: 20 additions & 0 deletions src/Server/HTTP/HTTPQueryAST.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <optional>

#include <Parsers/IAST_fwd.h>
#include <Server/HTTP/HTMLForm.h>

namespace DB
{

struct HTTPQueryAST
{
std::vector<ASTPtr> select_expressions;
std::vector<ASTPtr> where_expressions;
std::vector<ASTPtr> order_expressions;
};

HTTPQueryAST getHTTPQueryAST(HTMLForm & params);

}
17 changes: 11 additions & 6 deletions src/Server/HTTPHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <Server/IServer.h>
#include <Common/logger_useful.h>
#include <Common/SettingsChanges.h>
#include <Common/StringUtils.h>
#include <Common/StringUtils/StringUtils.h>
#include <Common/scope_guard_safe.h>
#include <Common/setThreadName.h>
#include <Common/typeid_cast.h>
Expand All @@ -39,6 +39,7 @@
#include <base/scope_guard.h>
#include <Server/HTTP/HTTPResponse.h>

#include "Parsers/formatAST.h"
#include "config.h"

#include <Poco/Base64Decoder.h>
Expand Down Expand Up @@ -707,11 +708,11 @@ void HTTPHandler::processQuery(
/// The data can also be compressed using incompatible internal algorithm. This is indicated by
/// 'decompress' query parameter.
std::unique_ptr<ReadBuffer> in_post_maybe_compressed;
bool is_in_post_compressed = false;
bool in_post_compressed = false;
if (params.getParsed<bool>("decompress", false))
{
in_post_maybe_compressed = std::make_unique<CompressedReadBuffer>(*in_post, /* allow_different_codecs_ = */ false, /* external_data_ = */ true);
is_in_post_compressed = true;
in_post_maybe_compressed = std::make_unique<CompressedReadBuffer>(*in_post);
in_post_compressed = true;
}
else
in_post_maybe_compressed = std::move(in_post);
Expand Down Expand Up @@ -837,6 +838,8 @@ void HTTPHandler::processQuery(
/// NOTE: this may create pretty huge allocations that will not be accounted in trace_log,
/// because memory_profiler_sample_probability/memory_profiler_step are not applied yet,
/// they will be applied in ProcessList::insert() from executeQuery() itself.

// here is query
const auto & query = getQuery(request, params, context);
std::unique_ptr<ReadBuffer> in_param = std::make_unique<ReadBufferFromString>(query);

Expand All @@ -845,7 +848,7 @@ void HTTPHandler::processQuery(

/// If 'http_native_compression_disable_checksumming_on_decompress' setting is turned on,
/// checksums of client data compressed with internal algorithm are not checked.
if (is_in_post_compressed && settings.http_native_compression_disable_checksumming_on_decompress)
if (in_post_compressed && settings.http_native_compression_disable_checksumming_on_decompress)
static_cast<CompressedReadBuffer &>(*in_post_maybe_compressed).disableChecksumming();

/// Add CORS header if 'add_http_cors_header' setting is turned on send * in Access-Control-Allow-Origin
Expand Down Expand Up @@ -934,6 +937,8 @@ void HTTPHandler::processQuery(
}
};

// auto query_data = getQueryData(*in, context);

executeQuery(
*in,
*used_output.out_maybe_delayed_and_compressed,
Expand Down Expand Up @@ -1108,7 +1113,7 @@ void HTTPHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse
client_trace_context,
context->getSettingsRef(),
context->getOpenTelemetrySpanLog());
thread_trace_context->root_span.kind = OpenTelemetry::SpanKind::SERVER;
thread_trace_context->root_span.kind = OpenTelemetry::SERVER;
thread_trace_context->root_span.addAttribute("clickhouse.uri", request.getURI());

response.setContentType("text/plain; charset=UTF-8");
Expand Down
98 changes: 98 additions & 0 deletions src/Server/TabularHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "TabularHandler.h"
#include "Parsers/ASTAsterisk.h"
#include "Parsers/ASTExpressionList.h"
#include "Parsers/ASTIdentifier.h"
#include "Parsers/ASTTablesInSelectQuery.h"
#include "Interpreters/executeQuery.h"

#include <Parsers/ASTSelectQuery.h>
#include "Parsers/ExpressionListParsers.h"
#include "Parsers/formatAST.h"

#include <optional>
#include <string>
#include <vector>

#include <Interpreters/Context.h>
#include <Poco/URI.h>

namespace DB
{

static const std::unordered_set<std::string> kQueryParameters = {"where", "columns", "select", "order", "format", "query"};
static constexpr auto kWhere = "where";

TabularHandler::TabularHandler(IServer & server_, const std::optional<String> & content_type_override_)
: HTTPHandler(server_, "TabularHandler", content_type_override_), log(getLogger("TabularHandler"))
{
}

std::string TabularHandler::getQuery(HTTPServerRequest & request, HTMLForm & /*params*/, ContextMutablePtr context)
{
auto uri = Poco::URI(request.getURI());

std::vector<std::string> path_segments;
uri.getPathSegments(path_segments);

const auto database = path_segments[1];
const auto table_with_format = path_segments[2];

auto pos = table_with_format.rfind('.');
std::string table = table_with_format.substr(0, pos);
std::string format = table_with_format.substr(pos + 1);

auto select_query = std::make_shared<ASTSelectQuery>();

auto select_expression_list = std::make_shared<ASTExpressionList>();
select_expression_list->children.push_back(std::make_shared<ASTAsterisk>());
select_query->setExpression(ASTSelectQuery::Expression::SELECT, select_expression_list);

auto table_expression = std::make_shared<ASTTableExpression>();
table_expression->database_and_table_name = std::make_shared<ASTTableIdentifier>(database, table);
auto tables_in_select_query = std::make_shared<ASTTablesInSelectQuery>();
auto tables_in_select_element = std::make_shared<ASTTablesInSelectQueryElement>();
tables_in_select_element->table_expression = table_expression;
tables_in_select_query->children.push_back(tables_in_select_element);
select_query->setExpression(ASTSelectQuery::Expression::TABLES, tables_in_select_query);

const auto & query_parameters = context->getQueryParameters();

if (query_parameters.contains(kWhere))
{
const auto & where_raw = query_parameters.at(kWhere);
ASTPtr where_expression;
Tokens tokens(where_raw.c_str(), where_raw.c_str() + where_raw.size());
IParser::Pos new_pos(tokens, 0, 0);
Expected expected;

ParserExpressionWithOptionalAlias(false).parse(new_pos, where_expression, expected);
select_query->setExpression(ASTSelectQuery::Expression::WHERE, std::move(where_expression));
}

// Convert AST to query string
WriteBufferFromOwnString query_buffer;
formatAST(*select_query, query_buffer, false);
std::string query_str = query_buffer.str();

// Append FORMAT clause
query_str += " FORMAT " + format;

LOG_INFO(log, "TabularHandler LOG {}", query_str);

return query_str;
// LOG_INFO(log, "TabularHandler LOG {}", request.getURI());
}


bool TabularHandler::customizeQueryParam(ContextMutablePtr context, const std::string & key, const std::string & value)
{
if (kQueryParameters.contains(key) && !context->getQueryParameters().contains(key))
{
context->setQueryParameter(key, value);
return true;
}

return false;
}

} // namespace DB
28 changes: 28 additions & 0 deletions src/Server/TabularHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <optional>
#include <string>

#include <Interpreters/Context_fwd.h>
#include <Server/HTTPHandler.h>
#include <Poco/Logger.h>

namespace DB
{

class TabularHandler : public HTTPHandler
{
private:
LoggerPtr log;

std::optional<std::string> where;

public:
TabularHandler(IServer & server_, const std::optional<String> & content_type_override_ = std::nullopt);

std::string getQuery(HTTPServerRequest & request, HTMLForm & params, ContextMutablePtr context) override;

bool customizeQueryParam(ContextMutablePtr context, const std::string & key, const std::string & value) override;
};

}

0 comments on commit ea7579e

Please sign in to comment.