Skip to content

Commit 623aef2

Browse files
Merge pull request ClickHouse#87668 from ClickHouse/backport/25.8/86480
Backport ClickHouse#86480 to 25.8: Fix detach/attach for postgres database engine tables with numeric/decimal columns
2 parents fb195bb + 9c6d7b5 commit 623aef2

File tree

3 files changed

+72
-34
lines changed

3 files changed

+72
-34
lines changed

src/Databases/PostgreSQL/DatabasePostgreSQL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <DataTypes/DataTypeNullable.h>
88
#include <DataTypes/DataTypeArray.h>
9+
#include <DataTypes/DataTypesDecimal.h>
910
#include <Storages/AlterCommands.h>
1011
#include <Storages/NamedCollectionsHelpers.h>
1112
#include <Storages/StoragePostgreSQL.h>
@@ -519,6 +520,9 @@ ASTPtr DatabasePostgreSQL::getColumnDeclaration(const DataTypePtr & data_type) c
519520
if (which.isDateTime64())
520521
return makeASTDataType("DateTime64", std::make_shared<ASTLiteral>(static_cast<UInt32>(6)));
521522

523+
if (which.isDecimal())
524+
return makeASTDataType("Decimal", std::make_shared<ASTLiteral>(getDecimalPrecision(*data_type)), std::make_shared<ASTLiteral>(getDecimalScale(*data_type)));
525+
522526
return makeASTDataType(data_type->getName());
523527
}
524528

src/Storages/PostgreSQL/StorageMaterializedPostgreSQL.cpp

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -331,42 +331,11 @@ ASTPtr StorageMaterializedPostgreSQL::getColumnDeclaration(const DataTypePtr & d
331331
if (which.isArray())
332332
return makeASTDataType("Array", getColumnDeclaration(typeid_cast<const DataTypeArray *>(data_type.get())->getNestedType()));
333333

334-
/// getName() for decimal returns 'Decimal(precision, scale)', will get an error with it
335-
if (which.isDecimal())
336-
{
337-
auto make_decimal_expression = [&](std::string type_name)
338-
{
339-
auto ast_expression = std::make_shared<ASTDataType>();
340-
341-
ast_expression->name = type_name;
342-
ast_expression->arguments = std::make_shared<ASTExpressionList>();
343-
ast_expression->arguments->children.emplace_back(std::make_shared<ASTLiteral>(getDecimalScale(*data_type)));
344-
345-
return ast_expression;
346-
};
347-
348-
if (which.isDecimal32())
349-
return make_decimal_expression("Decimal32");
350-
351-
if (which.isDecimal64())
352-
return make_decimal_expression("Decimal64");
353-
354-
if (which.isDecimal128())
355-
return make_decimal_expression("Decimal128");
356-
357-
if (which.isDecimal256())
358-
return make_decimal_expression("Decimal256");
359-
}
360-
361334
if (which.isDateTime64())
362-
{
363-
auto ast_expression = std::make_shared<ASTDataType>();
335+
return makeASTDataType("DateTime64", std::make_shared<ASTLiteral>(static_cast<UInt32>(6)));
364336

365-
ast_expression->name = "DateTime64";
366-
ast_expression->arguments = std::make_shared<ASTExpressionList>();
367-
ast_expression->arguments->children.emplace_back(std::make_shared<ASTLiteral>(static_cast<UInt32>(6)));
368-
return ast_expression;
369-
}
337+
if (which.isDecimal())
338+
return makeASTDataType("Decimal", std::make_shared<ASTLiteral>(getDecimalPrecision(*data_type)), std::make_shared<ASTLiteral>(getDecimalScale(*data_type)));
370339

371340
return makeASTDataType(data_type->getName());
372341
}

tests/integration/test_postgresql_database_engine/test.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,71 @@ def test_datetime(started_cluster):
403403
assert "DateTime64(6)" in node1.query("show create table pg.test")
404404

405405

406+
def test_numeric_detach_attach(started_cluster):
407+
cursor = started_cluster.postgres_conn.cursor()
408+
cursor.execute("DROP TABLE IF EXISTS test_table")
409+
cursor.execute("""
410+
CREATE TABLE test_table (
411+
numeric_1 numeric NOT NULL,
412+
numeric_2 numeric(10) NOT NULL,
413+
numeric_3 numeric(10, 0) NOT NULL,
414+
numeric_4 numeric(5, 2) NOT NULL,
415+
numeric_5 numeric(10, 5) NOT NULL,
416+
numeric_6 numeric(20, 10) NOT NULL,
417+
numeric_7 numeric(50, 20) NOT NULL,
418+
decimal_1 decimal NOT NULL,
419+
decimal_2 decimal(10) NOT NULL,
420+
decimal_3 decimal(10, 0) NOT NULL,
421+
decimal_4 decimal(5, 2) NOT NULL,
422+
decimal_5 decimal(10, 5) NOT NULL,
423+
decimal_6 decimal(20, 10) NOT NULL,
424+
decimal_7 decimal(50, 20) NOT NULL
425+
)
426+
""")
427+
428+
node1.query("DROP DATABASE IF EXISTS postgres_database")
429+
node1.query(
430+
"CREATE DATABASE postgres_database ENGINE = PostgreSQL(postgres1)"
431+
)
432+
433+
expected_clickhouse_column_types = {
434+
"numeric_1": "Decimal(38, 19)",
435+
"numeric_2": "Decimal(10, 0)",
436+
"numeric_3": "Decimal(10, 0)",
437+
"numeric_4": "Decimal(5, 2)",
438+
"numeric_5": "Decimal(10, 5)",
439+
"numeric_6": "Decimal(20, 10)",
440+
"numeric_7": "Decimal(50, 20)",
441+
"decimal_1": "Decimal(38, 19)",
442+
"decimal_2": "Decimal(10, 0)",
443+
"decimal_3": "Decimal(10, 0)",
444+
"decimal_4": "Decimal(5, 2)",
445+
"decimal_5": "Decimal(10, 5)",
446+
"decimal_6": "Decimal(20, 10)",
447+
"decimal_7": "Decimal(50, 20)",
448+
}
449+
450+
def get_actual_clickhouse_column_types():
451+
res = node1.query(
452+
"SELECT name, type FROM system.columns WHERE database = 'postgres_database' AND table = 'test_table'"
453+
)
454+
455+
return dict(line.split('\t') for line in res.splitlines())
456+
457+
assert get_actual_clickhouse_column_types() == expected_clickhouse_column_types
458+
459+
create_ddl = node1.query("SHOW CREATE TABLE postgres_database.test_table")
460+
for column, expected_type in expected_clickhouse_column_types.items():
461+
assert f"`{column}` {expected_type}" in create_ddl
462+
463+
node1.query("DETACH TABLE postgres_database.test_table")
464+
node1.query("ATTACH TABLE postgres_database.test_table")
465+
466+
assert get_actual_clickhouse_column_types() == expected_clickhouse_column_types
467+
468+
node1.query("DROP DATABASE postgres_database")
469+
cursor.execute(f"DROP TABLE test_table")
470+
406471
def test_postgresql_password_leak(started_cluster):
407472
conn = get_postgres_conn(
408473
started_cluster.postgres_ip, started_cluster.postgres_port, database=True

0 commit comments

Comments
 (0)