1#include <type_traits>
2#include <ext/scope_guard.h>
3
4#include <Core/Defines.h>
5#include <DataTypes/DataTypeFactory.h>
6#include <IO/ReadHelpers.h>
7#include <IO/ReadWriteBufferFromHTTP.h>
8#include <Interpreters/evaluateConstantExpression.h>
9#include <Parsers/ASTFunction.h>
10#include <Parsers/ASTLiteral.h>
11#include <Parsers/parseQuery.h>
12#include <Storages/StorageXDBC.h>
13#include <TableFunctions/ITableFunction.h>
14#include <TableFunctions/ITableFunctionXDBC.h>
15#include <TableFunctions/TableFunctionFactory.h>
16#include <Poco/Net/HTTPRequest.h>
17#include <Common/Exception.h>
18#include <Common/typeid_cast.h>
19#include <Poco/NumberFormatter.h>
20#include "registerTableFunctions.h"
21
22namespace DB
23{
24namespace ErrorCodes
25{
26 extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
27 extern const int UNKNOWN_EXCEPTION;
28 extern const int LOGICAL_ERROR;
29}
30
31StoragePtr ITableFunctionXDBC::executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const
32{
33 const auto & args_func = ast_function->as<ASTFunction &>();
34
35 if (!args_func.arguments)
36 throw Exception("Table function '" + getName() + "' must have arguments.", ErrorCodes::LOGICAL_ERROR);
37
38 ASTs & args = args_func.arguments->children;
39 if (args.size() != 2 && args.size() != 3)
40 throw Exception("Table function '" + getName() + "' requires 2 or 3 arguments: " + getName() + "('DSN', table) or " + getName()
41 + "('DSN', schema, table)",
42 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
43
44 for (auto i = 0u; i < args.size(); ++i)
45 args[i] = evaluateConstantExpressionOrIdentifierAsLiteral(args[i], context);
46
47 std::string connection_string;
48 std::string schema_name;
49 std::string remote_table_name;
50
51 if (args.size() == 3)
52 {
53 connection_string = args[0]->as<ASTLiteral &>().value.safeGet<String>();
54 schema_name = args[1]->as<ASTLiteral &>().value.safeGet<String>();
55 remote_table_name = args[2]->as<ASTLiteral &>().value.safeGet<String>();
56 }
57 else if (args.size() == 2)
58 {
59 connection_string = args[0]->as<ASTLiteral &>().value.safeGet<String>();
60 remote_table_name = args[1]->as<ASTLiteral &>().value.safeGet<String>();
61 }
62
63 /* Infer external table structure */
64 /// Have to const_cast, because bridges store their commands inside context
65 BridgeHelperPtr helper = createBridgeHelper(const_cast<Context &>(context), context.getSettingsRef().http_receive_timeout.value, connection_string);
66 helper->startBridgeSync();
67
68 Poco::URI columns_info_uri = helper->getColumnsInfoURI();
69 columns_info_uri.addQueryParameter("connection_string", connection_string);
70 if (!schema_name.empty())
71 columns_info_uri.addQueryParameter("schema", schema_name);
72 columns_info_uri.addQueryParameter("table", remote_table_name);
73
74 const auto use_nulls = context.getSettingsRef().external_table_functions_use_nulls;
75 columns_info_uri.addQueryParameter("external_table_functions_use_nulls",
76 Poco::NumberFormatter::format(use_nulls));
77
78 ReadWriteBufferFromHTTP buf(columns_info_uri, Poco::Net::HTTPRequest::HTTP_POST, nullptr);
79
80 std::string columns_info;
81 readStringBinary(columns_info, buf);
82 NamesAndTypesList columns = NamesAndTypesList::parse(columns_info);
83
84 auto result = std::make_shared<StorageXDBC>(getDatabaseName(), table_name, schema_name, remote_table_name, ColumnsDescription{columns}, context, helper);
85
86 if (!result)
87 throw Exception("Failed to instantiate storage from table function " + getName(), ErrorCodes::UNKNOWN_EXCEPTION);
88
89 result->startup();
90 return result;
91}
92
93void registerTableFunctionJDBC(TableFunctionFactory & factory)
94{
95 factory.registerFunction<TableFunctionJDBC>();
96}
97
98void registerTableFunctionODBC(TableFunctionFactory & factory)
99{
100 factory.registerFunction<TableFunctionODBC>();
101}
102}
103