ClickHouse
109 строк · 3.5 Кб
1#include "SchemaAllowedHandler.h"
2
3#if USE_ODBC
4
5#include <Server/HTTP/HTMLForm.h>
6#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
7#include <IO/ReadHelpers.h>
8#include <IO/WriteHelpers.h>
9#include <Poco/Net/HTTPServerRequest.h>
10#include <Poco/Net/HTTPServerResponse.h>
11#include <Common/BridgeProtocolVersion.h>
12#include <Common/logger_useful.h>
13#include "validateODBCConnectionString.h"
14#include "ODBCPooledConnectionFactory.h"
15#include <sql.h>
16#include <sqlext.h>
17
18
19namespace DB
20{
21namespace
22{
23bool isSchemaAllowed(nanodbc::ConnectionHolderPtr connection_holder)
24{
25uint32_t result = execute<uint32_t>(connection_holder,
26[&](nanodbc::connection & connection) { return connection.get_info<uint32_t>(SQL_SCHEMA_USAGE); });
27return result != 0;
28}
29}
30
31
32void SchemaAllowedHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response, const ProfileEvents::Event & /*write_event*/)
33{
34HTMLForm params(getContext()->getSettingsRef(), request, request.getStream());
35LOG_TRACE(log, "Request URI: {}", request.getURI());
36
37auto process_error = [&response, this](const std::string & message)
38{
39response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
40if (!response.sent())
41*response.send() << message << '\n';
42LOG_WARNING(log, fmt::runtime(message));
43};
44
45size_t version;
46
47if (!params.has("version"))
48version = 0; /// assumed version for too old servers which do not send a version
49else
50{
51String version_str = params.get("version");
52if (!tryParse(version, version_str))
53{
54process_error("Unable to parse 'version' string in request URL: '" + version_str + "' Check if the server and library-bridge have the same version.");
55return;
56}
57}
58
59if (version != XDBC_BRIDGE_PROTOCOL_VERSION)
60{
61/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
62process_error("Server and library-bridge have different versions: '" + std::to_string(version) + "' vs. '" + std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION) + "'");
63return;
64}
65
66
67if (!params.has("connection_string"))
68{
69process_error("No 'connection_string' in request URL");
70return;
71}
72
73bool use_connection_pooling = params.getParsed<bool>("use_connection_pooling", true);
74
75try
76{
77std::string connection_string = params.get("connection_string");
78
79nanodbc::ConnectionHolderPtr connection;
80
81if (use_connection_pooling)
82connection = ODBCPooledConnectionFactory::instance().get(
83validateODBCConnectionString(connection_string), getContext()->getSettingsRef().odbc_bridge_connection_pool_size);
84else
85connection = std::make_shared<nanodbc::ConnectionHolder>(validateODBCConnectionString(connection_string));
86
87bool result = isSchemaAllowed(std::move(connection));
88
89WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout);
90try
91{
92writeBoolText(result, out);
93out.finalize();
94}
95catch (...)
96{
97out.finalize();
98}
99}
100catch (...)
101{
102process_error("Error getting schema usage from ODBC '" + getCurrentExceptionMessage(false) + "'");
103tryLogCurrentException(log);
104}
105}
106
107}
108
109#endif
110