mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 08:40:50 +00:00
odbc table function now respects external_table_functions_use_nulls setting
* Passing setting value to ODBC-bridge on each request * Handling that setting value correctly in ODBC-bridge * Fixed issue with executing table-functions on context with no settings applied in `SELECT ... SETTINGS x=foo` query. * Added tests to verify fix.
This commit is contained in:
parent
5cf36f66ea
commit
5624bb3abb
@ -18,6 +18,7 @@
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
#include <Poco/Net/HTTPServerResponse.h>
|
||||
#include <Poco/Net/HTMLForm.h>
|
||||
#include <Poco/NumberParser.h>
|
||||
#include <DataTypes/DataTypeFactory.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <IO/WriteBufferFromHTTPServerResponse.h>
|
||||
@ -62,6 +63,15 @@ namespace
|
||||
return factory.get("String");
|
||||
}
|
||||
}
|
||||
|
||||
bool parseBool(const std::string & s, bool default_value = false)
|
||||
{
|
||||
bool result;
|
||||
if (Poco::NumberParser::tryParseBool(s, result))
|
||||
return result;
|
||||
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ErrorCodes
|
||||
@ -95,6 +105,8 @@ void ODBCColumnsInfoHandler::handleRequest(Poco::Net::HTTPServerRequest & reques
|
||||
std::string schema_name = "";
|
||||
std::string table_name = params.get("table");
|
||||
std::string connection_string = params.get("connection_string");
|
||||
const bool external_table_functions_use_nulls = parseBool(params.get("external_table_functions_use_nulls", "false"));
|
||||
|
||||
if (params.has("schema"))
|
||||
{
|
||||
schema_name = params.get("schema");
|
||||
@ -160,13 +172,13 @@ void ODBCColumnsInfoHandler::handleRequest(Poco::Net::HTTPServerRequest & reques
|
||||
/// TODO Why 301?
|
||||
SQLCHAR column_name[301];
|
||||
|
||||
SQLSMALLINT nullable;
|
||||
const auto result = POCO_SQL_ODBC_CLASS::SQLDescribeCol(hstmt, ncol, column_name, sizeof(column_name), nullptr, &type, nullptr, nullptr, &nullable);
|
||||
SQLSMALLINT is_nullable;
|
||||
const auto result = POCO_SQL_ODBC_CLASS::SQLDescribeCol(hstmt, ncol, column_name, sizeof(column_name), nullptr, &type, nullptr, nullptr, &is_nullable);
|
||||
if (POCO_SQL_ODBC_CLASS::Utility::isError(result))
|
||||
throw POCO_SQL_ODBC_CLASS::StatementException(hstmt);
|
||||
|
||||
auto column_type = getDataType(type);
|
||||
if (nullable == SQL_NULLABLE)
|
||||
if (external_table_functions_use_nulls && is_nullable == SQL_NULLABLE)
|
||||
{
|
||||
column_type = std::make_shared<DataTypeNullable>(column_type);
|
||||
}
|
||||
|
@ -357,7 +357,7 @@ struct Settings : public SettingsCollection<Settings>
|
||||
M(SettingBool, allow_experimental_multiple_joins_emulation, true, "Emulate multiple joins using subselects") \
|
||||
M(SettingBool, allow_experimental_cross_to_join_conversion, true, "Convert CROSS JOIN to INNER JOIN if possible") \
|
||||
M(SettingBool, cancel_http_readonly_queries_on_client_close, false, "Cancel HTTP readonly queries when a client closes the connection without waiting for response.") \
|
||||
M(SettingBool, external_table_functions_use_nulls, true, "If it is set to true, external table functions will implicitly use Nullable type if needed. Otherwise NULLs will be substituted with default values. Currently supported only for 'mysql' table function.") \
|
||||
M(SettingBool, external_table_functions_use_nulls, true, "If it is set to true, external table functions will implicitly use Nullable type if needed. Otherwise NULLs will be substituted with default values. Currently supported only by 'mysql' and 'odbc' table functions.") \
|
||||
M(SettingBool, allow_experimental_data_skipping_indices, false, "If it is set to true, data skipping indices can be used in CREATE TABLE/ALTER TABLE queries.") \
|
||||
\
|
||||
M(SettingBool, experimental_use_processors, false, "Use processors pipeline.") \
|
||||
|
@ -286,8 +286,9 @@ InterpreterSelectQuery::InterpreterSelectQuery(
|
||||
{
|
||||
if (is_table_func)
|
||||
{
|
||||
/// Read from table function.
|
||||
storage = context.getQueryContext().executeTableFunction(table_expression);
|
||||
/// Read from table function. propagate all settings from initSettings(),
|
||||
/// alternative is to call on current `context`, but that can potentially pollute it.
|
||||
storage = getSubqueryContext(context).executeTableFunction(table_expression);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <Poco/Net/HTTPRequest.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Poco/NumberFormatter.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -70,6 +71,10 @@ StoragePtr ITableFunctionXDBC::executeImpl(const ASTPtr & ast_function, const Co
|
||||
columns_info_uri.addQueryParameter("schema", schema_name);
|
||||
columns_info_uri.addQueryParameter("table", remote_table_name);
|
||||
|
||||
const auto use_nuls = context.getSettingsRef().external_table_functions_use_nulls;
|
||||
columns_info_uri.addQueryParameter("external_table_functions_use_nulls",
|
||||
Poco::NumberFormatter::format(use_nuls));
|
||||
|
||||
ReadWriteBufferFromHTTP buf(columns_info_uri, Poco::Net::HTTPRequest::HTTP_POST, nullptr);
|
||||
|
||||
std::string columns_info;
|
||||
|
@ -91,7 +91,8 @@ def test_mysql_simple_select_works(started_cluster):
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("INSERT INTO clickhouse.{} VALUES(50, 'null-guy', 127, 255, NULL), (100, 'non-null-guy', 127, 255, 511);".format(table_name))
|
||||
conn.commit()
|
||||
assert node1.query("SELECT column_x FROM odbc('DSN={}', '{}')".format(mysql_setup["DSN"], table_name)) == '\\N\n511\n'
|
||||
assert node1.query("SELECT column_x FROM odbc('DSN={}', '{}') SETTINGS external_table_functions_use_nulls=1".format(mysql_setup["DSN"], table_name)) == '\\N\n511\n'
|
||||
assert node1.query("SELECT column_x FROM odbc('DSN={}', '{}') SETTINGS external_table_functions_use_nulls=0".format(mysql_setup["DSN"], table_name)) == '0\n511\n'
|
||||
|
||||
node1.query('''
|
||||
CREATE TABLE {}(id UInt32, name String, age UInt32, money UInt32, column_x Nullable(UInt32)) ENGINE = MySQL('mysql1:3306', 'clickhouse', '{}', 'root', 'clickhouse');
|
||||
|
Loading…
Reference in New Issue
Block a user