diff --git a/dbms/programs/client/Client.cpp b/dbms/programs/client/Client.cpp index 3ffe255a5a7f5360fde286e9f1177f699076dda4..ab44dd7d59065946631b2e3d58bc49417a750a13 100644 --- a/dbms/programs/client/Client.cpp +++ b/dbms/programs/client/Client.cpp @@ -106,6 +106,7 @@ namespace ErrorCodes extern const int CANNOT_SET_SIGNAL_HANDLER; extern const int CANNOT_READLINE; extern const int SYSTEM_ERROR; + extern const int INVALID_USAGE_OF_INPUT; } @@ -845,7 +846,7 @@ private: if (insert && (!insert->select || input_function)) { if (input_function && insert->format.empty()) - throw Exception("FORMAT must be specified for function input()", ErrorCodes::LOGICAL_ERROR); + throw Exception("FORMAT must be specified for function input()", ErrorCodes::INVALID_USAGE_OF_INPUT); processInsertQuery(); } else diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index fd058f1fbe07e7146857f0e88c6b6b5eda110a77..9a9197d4e8cde96e0eb343770153ab75419c7cdc 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -449,6 +449,7 @@ namespace ErrorCodes extern const int READONLY_SETTING = 472; extern const int DEADLOCK_AVOIDED = 473; extern const int INVALID_TEMPLATE_FORMAT = 474; + extern const int INVALID_USAGE_OF_INPUT = 475; extern const int KEEPER_EXCEPTION = 999; extern const int POCO_EXCEPTION = 1000; diff --git a/dbms/src/DataStreams/InputStreamFromASTInsertQuery.cpp b/dbms/src/DataStreams/InputStreamFromASTInsertQuery.cpp index e55f1ddd32e989d4f00c71efe8ce7055e9df1b09..bf31f55c61084ea7b75e1daf8c790aaae8dc8d9d 100644 --- a/dbms/src/DataStreams/InputStreamFromASTInsertQuery.cpp +++ b/dbms/src/DataStreams/InputStreamFromASTInsertQuery.cpp @@ -16,6 +16,7 @@ namespace DB namespace ErrorCodes { extern const int LOGICAL_ERROR; + extern const int INVALID_USAGE_OF_INPUT; } @@ -31,7 +32,7 @@ InputStreamFromASTInsertQuery::InputStreamFromASTInsertQuery( if (format.empty()) { if (input_function) - throw Exception("FORMAT must be specified for function input()", ErrorCodes::LOGICAL_ERROR); + throw Exception("FORMAT must be specified for function input()", ErrorCodes::INVALID_USAGE_OF_INPUT); format = "Values"; } diff --git a/dbms/src/Parsers/ASTInsertQuery.cpp b/dbms/src/Parsers/ASTInsertQuery.cpp index 77565306621851380025e5be68b11f72bd28b772..1ac92f49735952638046466a7d71dff1f34589fe 100644 --- a/dbms/src/Parsers/ASTInsertQuery.cpp +++ b/dbms/src/Parsers/ASTInsertQuery.cpp @@ -8,7 +8,7 @@ namespace DB namespace ErrorCodes { - extern const int LOGICAL_ERROR; + extern const int INVALID_USAGE_OF_INPUT; } @@ -70,7 +70,7 @@ void tryFindInputFunctionImpl(const ASTPtr & ast, ASTPtr & input_function) if (table_function_ast->name == "input") { if (input_function) - throw Exception("You can use 'input()' function only once per request.", ErrorCodes::LOGICAL_ERROR); + throw Exception("You can use 'input()' function only once per request.", ErrorCodes::INVALID_USAGE_OF_INPUT); input_function = ast; } } diff --git a/dbms/src/Storages/StorageInput.cpp b/dbms/src/Storages/StorageInput.cpp index 37ca36413bd45c428f755c0e1fae3ff16e57c74a..38424f226321668fdf95ac22ef66a875ad8bcce6 100644 --- a/dbms/src/Storages/StorageInput.cpp +++ b/dbms/src/Storages/StorageInput.cpp @@ -12,12 +12,13 @@ namespace DB namespace ErrorCodes { - extern const int LOGICAL_ERROR; + extern const int INVALID_USAGE_OF_INPUT; } StorageInput::StorageInput(const String &table_name_, const ColumnsDescription & columns_) : IStorage(columns_), table_name(table_name_) { + setColumns(columns_); } @@ -67,7 +68,7 @@ BlockInputStreams StorageInput::read(const Names & /*column_names*/, } if (!input_stream) - throw Exception("Input stream is not initialized, input() must be used only in INSERT SELECT query", ErrorCodes::LOGICAL_ERROR); + throw Exception("Input stream is not initialized, input() must be used only in INSERT SELECT query", ErrorCodes::INVALID_USAGE_OF_INPUT); return {input_stream}; } diff --git a/dbms/src/TableFunctions/TableFunctionInput.cpp b/dbms/src/TableFunctions/TableFunctionInput.cpp index 3c71123e145618ba0b20aafa44e43ed436c2e613..d6d16c3c907723174557d8655587c874a92c894d 100644 --- a/dbms/src/TableFunctions/TableFunctionInput.cpp +++ b/dbms/src/TableFunctions/TableFunctionInput.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -33,29 +34,9 @@ StoragePtr TableFunctionInput::executeImpl(const ASTPtr & ast_function, const Co throw Exception("Table function '" + getName() + "' requires exactly 1 argument: structure", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(args[0], context); String structure = evaluateConstantExpressionOrIdentifierAsLiteral(args[0], context)->as().value.safeGet(); - - // Create sample block - Strings structure_vals; - boost::split(structure_vals, structure, boost::algorithm::is_any_of(" ,"), boost::algorithm::token_compress_on); - - if (structure_vals.size() % 2 != 0) - throw Exception("Odd number of elements in section structure: must be a list of name type pairs", ErrorCodes::LOGICAL_ERROR); - - Block sample_block; - const DataTypeFactory & data_type_factory = DataTypeFactory::instance(); - - for (size_t i = 0, size = structure_vals.size(); i < size; i += 2) - { - ColumnWithTypeAndName column; - column.name = structure_vals[i]; - column.type = data_type_factory.get(structure_vals[i + 1]); - column.column = column.type->createColumn(); - sample_block.insert(std::move(column)); - } - - StoragePtr storage = StorageInput::create(table_name, ColumnsDescription{sample_block.getNamesAndTypesList()}); + auto columns = parseColumnsListFromString(structure, context); + StoragePtr storage = StorageInput::create(table_name, columns); storage->startup(); diff --git a/dbms/tests/queries/0_stateless/00952_input_function.sh b/dbms/tests/queries/0_stateless/00952_input_function.sh index 7919c0a33fce12c03a3713dbe13ef7802cfc92ca..085ae496fafb99251a4154744dba38b0bb1b6b3f 100755 --- a/dbms/tests/queries/0_stateless/00952_input_function.sh +++ b/dbms/tests/queries/0_stateless/00952_input_function.sh @@ -18,12 +18,12 @@ ${CLICKHOUSE_CLIENT} --query="SELECT * FROM input_function_table_2 FORMAT CSV" ${CLICKHOUSE_CLIENT} --query="DROP TABLE IF EXISTS input_function_table_3" ${CLICKHOUSE_CLIENT} --query="CREATE TABLE input_function_table_3 (a String, b Date, c Int32, d Int16) ENGINE=Memory()" -cat ${CLICKHOUSE_TMP}/data_for_input_function.csv | ${CLICKHOUSE_CLIENT} --query="INSERT INTO input_function_table_3 (a, b, c) SELECT * FROM (SELECT a, b, c*c FROM input('a String, b Int32, c Int32') JOIN input_function_table_1 ON a=input_function_table_1.a) FORMAT CSV" +cat ${CLICKHOUSE_TMP}/data_for_input_function.csv | ${CLICKHOUSE_CLIENT} --query="INSERT INTO input_function_table_3 (a, b, c) SELECT * FROM (SELECT s, b, c*c FROM input('s String, b Int32, c Int32') JOIN input_function_table_1 ON s=input_function_table_1.a) FORMAT CSV" ${CLICKHOUSE_CLIENT} --query="SELECT * FROM input_function_table_3 FORMAT CSV" ${CLICKHOUSE_CLIENT} --query="DROP TABLE IF EXISTS input_function_table_4" ${CLICKHOUSE_CLIENT} --query="CREATE TABLE input_function_table_4 (a String, b Date, c Int32, d Int16) ENGINE=Memory()" -cat ${CLICKHOUSE_TMP}/data_for_input_function.csv | ${CLICKHOUSE_CURL} -sS "${CLICKHOUSE_URL_PARAMS}&query=INSERT%20INTO%20input_function_table_4%20%28a%2C%20b%2C%20c%29%20SELECT%20%2A%20FROM%20%28SELECT%20a%2C%20b%2C%20c%2Ac%20FROM%20input%28%27a%20String%2C%20b%20Int32%2C%20c%20Int32%27%29%20JOIN%20input_function_table_1%20ON%20a%3Dinput_function_table_1.a%29%20FORMAT%20CSV" --data-binary @- +cat ${CLICKHOUSE_TMP}/data_for_input_function.csv | ${CLICKHOUSE_CURL} -sS "${CLICKHOUSE_URL_PARAMS}&query=INSERT%20INTO%20input_function_table_4%20%28a%2C%20b%2C%20c%29%20SELECT%20%2A%20FROM%20%28SELECT%20s%2C%20b%2C%20c%2Ac%20FROM%20input%28%27s%20String%2C%20b%20Int32%2C%20c%20Int32%27%29%20JOIN%20input_function_table_1%20ON%20s%3Dinput_function_table_1.a%29%20FORMAT%20CSV" --data-binary @- ${CLICKHOUSE_CLIENT} --query="SELECT * FROM input_function_table_4 FORMAT CSV"