Add field output_columns to first Result sent in gRPC protocol.

This commit is contained in:
Vitaly Baranov 2022-02-08 20:15:56 +07:00
parent bd746fd82b
commit cf2e205b08
3 changed files with 31 additions and 4 deletions

View File

@ -644,6 +644,7 @@ namespace
void addQueryDetailsToResult();
void addOutputFormatToResult();
void addOutputColumnsNamesAndTypesToResult(const Block & headers);
void addProgressToResult();
void addTotalsToResult(const Block & totals);
void addExtremesToResult(const Block & extremes);
@ -669,6 +670,7 @@ namespace
CompressionMethod input_compression_method = CompressionMethod::None;
PODArray<char> output;
String output_format;
bool send_output_columns_names_and_types = false;
CompressionMethod output_compression_method = CompressionMethod::None;
int output_compression_level = 0;
@ -890,6 +892,8 @@ namespace
if (output_format.empty())
output_format = query_context->getDefaultFormat();
send_output_columns_names_and_types = query_info.send_output_columns();
/// Choose compression.
String input_compression_method_str = query_info.input_compression_type();
if (input_compression_method_str.empty())
@ -1195,6 +1199,7 @@ namespace
};
addOutputFormatToResult();
addOutputColumnsNamesAndTypesToResult(header);
Block block;
while (check_for_cancel())
@ -1457,6 +1462,18 @@ namespace
*result.mutable_output_format() = output_format;
}
void Call::addOutputColumnsNamesAndTypesToResult(const Block & header)
{
if (!send_output_columns_names_and_types)
return;
for (const auto & column : header)
{
auto & name_and_type = *result.add_output_columns();
*name_and_type.mutable_name() = column.name;
*name_and_type.mutable_type() = column.type->getName();
}
}
void Call::addProgressToResult()
{
auto values = progress.fetchAndResetPiecewiseAtomically();

View File

@ -82,6 +82,9 @@ message QueryInfo {
// Default output format. If not specified, 'TabSeparated' is used.
string output_format = 7;
// Set it if you want the names and the types of output columns to be sent to the client.
bool send_output_columns = 24;
repeated ExternalTable external_tables = 8;
string user_name = 9;
@ -194,6 +197,9 @@ message Result {
// It's either the same as `output_format` specified in `QueryInfo` or the format specified in the query itself.
string output_format = 11;
// The names and types of columns of the result written in `output`.
repeated NameAndType output_columns = 12;
// Output of the query, represented in the `output_format`.
bytes output = 1;
bytes totals = 2;

View File

@ -45,8 +45,8 @@ def create_channel():
main_channel = channel
return channel
def query_common(query_text, settings={}, input_data=[], input_data_delimiter='', output_format='TabSeparated', external_tables=[],
user_name='', password='', query_id='123', session_id='', stream_output=False, channel=None):
def query_common(query_text, settings={}, input_data=[], input_data_delimiter='', output_format='TabSeparated', send_output_columns=False,
external_tables=[], user_name='', password='', query_id='123', session_id='', stream_output=False, channel=None):
if type(input_data) is not list:
input_data = [input_data]
if type(input_data_delimiter) is str:
@ -60,7 +60,8 @@ def query_common(query_text, settings={}, input_data=[], input_data_delimiter=''
input_data_part = input_data_part.encode(DEFAULT_ENCODING)
return clickhouse_grpc_pb2.QueryInfo(query=query_text, settings=settings, input_data=input_data_part,
input_data_delimiter=input_data_delimiter, output_format=output_format,
external_tables=external_tables, user_name=user_name, password=password, query_id=query_id,
send_output_columns=send_output_columns, external_tables=external_tables,
user_name=user_name, password=password, query_id=query_id,
session_id=session_id, next_query_info=bool(input_data))
def send_query_info():
yield query_info()
@ -211,18 +212,21 @@ def test_get_query_details():
assert result.query_id == '123'
pytz.timezone(result.time_zone)
assert result.output_format == ''
assert len(result.output_columns) == 0
assert result.output == b''
#
result = list(query_no_errors("SELECT 'a', 1", query_id = '', output_format = 'TabSeparated'))[0]
uuid.UUID(result.query_id)
pytz.timezone(result.time_zone)
assert result.output_format == 'TabSeparated'
assert len(result.output_columns) == 0
assert result.output == b'a\t1\n'
#
result = list(query_no_errors("SELECT 'a' AS x, 1 FORMAT JSONEachRow", query_id = ''))[0]
result = list(query_no_errors("SELECT 'a' AS x, 1 FORMAT JSONEachRow", query_id = '', send_output_columns=True))[0]
uuid.UUID(result.query_id)
pytz.timezone(result.time_zone)
assert result.output_format == 'JSONEachRow'
assert ([(col.name, col.type) for col in result.output_columns]) == [('x', 'String'), ('1', 'UInt8')]
assert result.output == b'{"x":"a","1":1}\n'
def test_errors_handling():