|
13 | 13 |
|
14 | 14 | #include <Columns/ColumnString.h>
|
15 | 15 |
|
| 16 | +#include <Formats/FormatSchemaInfo.h> |
| 17 | + |
| 18 | +#include <IO/ReadBufferFromFile.h> |
| 19 | +#include <IO/ReadHelpers.h> |
16 | 20 | #include <IO/WriteBufferFromFile.h>
|
17 | 21 | #include <IO/WriteHelpers.h>
|
18 | 22 |
|
|
26 | 30 | #include <Parsers/parseQuery.h>
|
27 | 31 | #include <Parsers/queryToString.h>
|
28 | 32 |
|
| 33 | +#include <Poco/JSON/Parser.h> |
| 34 | +#include <Poco/Dynamic/Var.h> |
| 35 | +#include <Poco/JSON/Object.h> |
| 36 | +#include <Poco/JSON/Array.h> |
| 37 | + |
29 | 38 | #include <Storages/StorageFactory.h>
|
30 | 39 | #include <Storages/StorageInMemoryMetadata.h>
|
31 | 40 | #include <Storages/Streaming/StorageStream.h>
|
@@ -1454,8 +1463,70 @@ BlockIO InterpreterCreateQuery::execute()
|
1454 | 1463 | /// CREATE|ATTACH DATABASE
|
1455 | 1464 | if (create.database && !create.table)
|
1456 | 1465 | return createDatabase(create);
|
1457 |
| - else |
1458 |
| - return createTable(create); |
| 1466 | +// else |
| 1467 | +// return createTable(create); |
| 1468 | + |
| 1469 | + /// CREATE EXTERNAL STREAM |
| 1470 | + if (create.is_external && create.storage && create.storage->settings) |
| 1471 | + { |
| 1472 | + // Extract data_schema from SETTINGS |
| 1473 | + auto * set_query = create.storage->settings; |
| 1474 | + for (const auto & change : set_query->changes) |
| 1475 | + { |
| 1476 | + if (change.name == "data_schema") |
| 1477 | + create.data_schema = change.value.safeGet<String>(); |
| 1478 | + } |
| 1479 | + // Automatically derive schema |
| 1480 | + if (!create.columns_list && create.data_schema) |
| 1481 | + { |
| 1482 | + // FORMAT SCHEMA JSON |
| 1483 | + FormatSchemaInfo schema_info(*create.data_schema, "Avro", false, getContext()->getApplicationType() == Context::ApplicationType::SERVER, getContext()->getFormatSchemaPath()); |
| 1484 | + String schema_path = schema_info.absoluteSchemaPath(); |
| 1485 | + |
| 1486 | + std::string avro_schema_json; |
| 1487 | + { |
| 1488 | + ReadBufferFromFile in(schema_path); |
| 1489 | + readStringUntilEOF(avro_schema_json, in); |
| 1490 | + } |
| 1491 | + |
| 1492 | + Poco::JSON::Parser parser; |
| 1493 | + Poco::Dynamic::Var parsed_result = parser.parse(avro_schema_json); |
| 1494 | + Poco::JSON::Object::Ptr schema_obj = parsed_result.extract<Poco::JSON::Object::Ptr>(); |
| 1495 | + |
| 1496 | + if (!schema_obj->has("fields")) |
| 1497 | + { |
| 1498 | + throw Exception("Invalid Avro schema: 'fields' not found in schema: " + *create.data_schema, |
| 1499 | + ErrorCodes::BAD_ARGUMENTS); |
| 1500 | + } |
| 1501 | + |
| 1502 | + Poco::JSON::Array::Ptr fields = schema_obj->getArray("fields"); |
| 1503 | + auto columns_list = std::make_shared<ASTColumns>(); |
| 1504 | + auto expr_list = std::make_shared<ASTExpressionList>(); |
| 1505 | + columns_list->columns = expr_list.get(); |
| 1506 | + columns_list->children.push_back(expr_list); |
| 1507 | + |
| 1508 | + for (size_t i = 0; i < fields->size(); ++i) |
| 1509 | + { |
| 1510 | + Poco::JSON::Object::Ptr field = fields->getObject(i); |
| 1511 | + String column_name = field->getValue<String>("name"); |
| 1512 | + String column_type = field->getValue<String>("type"); |
| 1513 | + |
| 1514 | + // Create ASTColumnDeclaration |
| 1515 | + auto column_decl = std::make_shared<ASTColumnDeclaration>(); |
| 1516 | + column_decl->name = column_name; |
| 1517 | + |
| 1518 | + // Change Avro type into ClickHouse Type |
| 1519 | + String clickhouse_type = DB::avroTypeToClickHouseType(column_type); |
| 1520 | + auto type_ast = std::make_shared<ASTIdentifier>(clickhouse_type); |
| 1521 | + column_decl->type = type_ast; |
| 1522 | + |
| 1523 | + expr_list->children.push_back(column_decl); |
| 1524 | + } |
| 1525 | + |
| 1526 | + create.set(create.columns_list, columns_list); |
| 1527 | + } |
| 1528 | + } |
| 1529 | + return createTable(create); |
1459 | 1530 | }
|
1460 | 1531 |
|
1461 | 1532 |
|
|
0 commit comments