aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormonster <monster@ydb.tech>2023-02-10 15:42:00 +0300
committermonster <monster@ydb.tech>2023-02-10 15:42:00 +0300
commitf1892ba708c7e291bd6809366b4b7c0bccc36d3e (patch)
tree516690bccde15878922c91db0971e296bb6b52f7
parentc5c1a23f428643e0fb6675b84dc4d7f00abf1ead (diff)
downloadydb-f1892ba708c7e291bd6809366b4b7c0bccc36d3e.tar.gz
pg types parametrization
-rw-r--r--ydb/core/grpc_services/resolve_local_db_table.cpp2
-rw-r--r--ydb/core/grpc_services/rpc_kh_describe.cpp5
-rw-r--r--ydb/core/grpc_services/rpc_load_rows.cpp52
-rw-r--r--ydb/core/grpc_services/rpc_log_store.cpp5
-rw-r--r--ydb/core/grpc_services/rpc_long_tx.cpp4
-rw-r--r--ydb/core/grpc_services/rpc_read_columns.cpp4
-rw-r--r--ydb/core/kqp/common/kqp_resolve.h1
-rw-r--r--ydb/core/kqp/compute_actor/kqp_scan_compute_actor.cpp2
-rw-r--r--ydb/core/kqp/executer_actor/kqp_data_executer.cpp8
-rw-r--r--ydb/core/kqp/executer_actor/kqp_executer_impl.h4
-rw-r--r--ydb/core/kqp/executer_actor/kqp_scan_executer.cpp6
-rw-r--r--ydb/core/kqp/executer_actor/kqp_tasks_graph.h5
-rw-r--r--ydb/core/kqp/gateway/kqp_metadata_loader.cpp4
-rw-r--r--ydb/core/kqp/provider/yql_kikimr_gateway.cpp6
-rw-r--r--ydb/core/kqp/provider/yql_kikimr_gateway.h11
-rw-r--r--ydb/core/kqp/provider/yql_kikimr_provider.cpp1
-rw-r--r--ydb/core/kqp/runtime/kqp_compute.h1
-rw-r--r--ydb/core/kqp/runtime/kqp_scan_data.cpp8
-rw-r--r--ydb/core/kqp/runtime/kqp_scan_data_ut.cpp40
-rw-r--r--ydb/core/kqp/runtime/kqp_stream_lookup_actor.cpp1
-rw-r--r--ydb/core/kqp/ut/pg/CMakeLists.darwin.txt2
-rw-r--r--ydb/core/kqp/ut/pg/CMakeLists.linux-aarch64.txt2
-rw-r--r--ydb/core/kqp/ut/pg/CMakeLists.linux.txt2
-rw-r--r--ydb/core/kqp/ut/pg/kqp_pg_ut.cpp917
-rw-r--r--ydb/core/persqueue/pq_impl.cpp8
-rw-r--r--ydb/core/protos/type_info.proto1
-rw-r--r--ydb/core/scheme/scheme_type_info.cpp4
-rw-r--r--ydb/core/scheme/scheme_type_info.h2
-rw-r--r--ydb/core/scheme/scheme_types_proto.cpp18
-rw-r--r--ydb/core/scheme/scheme_types_proto.h9
-rw-r--r--ydb/core/sys_view/common/schema.cpp2
-rw-r--r--ydb/core/tablet_flat/flat_cxx_database.h2
-rw-r--r--ydb/core/tablet_flat/flat_dbase_apply.cpp23
-rw-r--r--ydb/core/tablet_flat/flat_dbase_apply.h2
-rw-r--r--ydb/core/tablet_flat/flat_dbase_scheme.cpp10
-rw-r--r--ydb/core/tablet_flat/flat_dbase_scheme.h2
-rw-r--r--ydb/core/tablet_flat/flat_executor.cpp3
-rw-r--r--ydb/core/tablet_flat/flat_table_column.h6
-rw-r--r--ydb/core/tablet_flat/flat_table_part.cpp6
-rw-r--r--ydb/core/tablet_flat/test/libs/rows/layout.h2
-rw-r--r--ydb/core/tablet_flat/ut_pg/flat_database_pg_ut.cpp20
-rw-r--r--ydb/core/tx/columnshard/columnshard_impl.cpp4
-rw-r--r--ydb/core/tx/columnshard/columnshard_ut_common.cpp2
-rw-r--r--ydb/core/tx/columnshard/columnshard_ut_common.h2
-rw-r--r--ydb/core/tx/columnshard/engines/ut_logs_engine.cpp2
-rw-r--r--ydb/core/tx/datashard/build_index.cpp5
-rw-r--r--ydb/core/tx/datashard/datashard_kqp.cpp5
-rw-r--r--ydb/core/tx/datashard/datashard_user_table.cpp14
-rw-r--r--ydb/core/tx/datashard/datashard_user_table.h4
-rw-r--r--ydb/core/tx/datashard/datashard_ut_common.cpp4
-rw-r--r--ydb/core/tx/datashard/import_common.h5
-rw-r--r--ydb/core/tx/datashard/import_s3.cpp14
-rw-r--r--ydb/core/tx/datashard/read_table_scan.cpp15
-rw-r--r--ydb/core/tx/datashard/sys_tables.h12
-rw-r--r--ydb/core/tx/scheme_board/cache.cpp9
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__init.cpp72
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_alter_olap_table.cpp4
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_create_cdc_stream.cpp2
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_create_external_table.cpp2
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp2
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_upgrade_subdomain.cpp2
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_impl.cpp13
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_info_types.cpp14
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_info_types.h4
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_path_describer.cpp12
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_utils.cpp8
-rw-r--r--ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp3
-rw-r--r--ydb/core/tx/tx_proxy/datareq.cpp2
-rw-r--r--ydb/core/tx/tx_proxy/describe.cpp5
-rw-r--r--ydb/core/tx/tx_proxy/read_table_impl.cpp8
-rw-r--r--ydb/core/tx/tx_proxy/upload_rows_common_impl.h46
-rw-r--r--ydb/core/ydb_convert/table_description.cpp62
-rw-r--r--ydb/core/ydb_convert/table_description.h3
-rw-r--r--ydb/core/yq/libs/result_formatter/result_formatter_ut.cpp1
-rw-r--r--ydb/library/mkql_proto/mkql_proto.cpp24
-rw-r--r--ydb/library/yql/parser/pg_wrapper/comp_factory.cpp256
-rw-r--r--ydb/library/yql/parser/pg_wrapper/interface/type_desc.h23
-rw-r--r--ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp32
-rw-r--r--ydb/public/api/protos/ydb_value.proto9
-rw-r--r--ydb/public/lib/json_value/ydb_json_value.cpp2
-rw-r--r--ydb/public/lib/json_value/ydb_json_value_ut.cpp2
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/value_helpers/helpers.cpp5
-rw-r--r--ydb/public/sdk/cpp/client/ydb_value/value.cpp14
-rw-r--r--ydb/public/sdk/cpp/client/ydb_value/value.h18
-rw-r--r--ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp4
85 files changed, 1351 insertions, 613 deletions
diff --git a/ydb/core/grpc_services/resolve_local_db_table.cpp b/ydb/core/grpc_services/resolve_local_db_table.cpp
index 3f1aeb74a58..81ae3d12a0c 100644
--- a/ydb/core/grpc_services/resolve_local_db_table.cpp
+++ b/ydb/core/grpc_services/resolve_local_db_table.cpp
@@ -45,7 +45,7 @@ namespace NGRpcService {
const NTable::TScheme::TTableInfo* tableInfo = scheme.Tables.FindPtr(*ti);
for (const auto& col : tableInfo->Columns) {
- entry.Columns[col.first] = TSysTables::TTableColumnInfo(col.second.Name, col.first, col.second.PType, col.second.KeyOrder);
+ entry.Columns[col.first] = TSysTables::TTableColumnInfo(col.second.Name, col.first, col.second.PType, col.second.PTypeMod, col.second.KeyOrder);
}
}
diff --git a/ydb/core/grpc_services/rpc_kh_describe.cpp b/ydb/core/grpc_services/rpc_kh_describe.cpp
index 1ceb70b9e1e..c5131ce14c5 100644
--- a/ydb/core/grpc_services/rpc_kh_describe.cpp
+++ b/ydb/core/grpc_services/rpc_kh_describe.cpp
@@ -178,7 +178,10 @@ private:
auto& typeInfo = col.second.PType;
auto* item = colMeta->mutable_type();
if (typeInfo.GetTypeId() == NScheme::NTypeIds::Pg) {
- item->mutable_pg_type()->set_oid(NPg::PgTypeIdFromTypeDesc(typeInfo.GetTypeDesc()));
+ auto* typeDesc = typeInfo.GetTypeDesc();
+ auto* pg = item->mutable_pg_type();
+ pg->set_type_name(NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_oid(NPg::PgTypeIdFromTypeDesc(typeDesc));
} else {
item->mutable_optional_type()->mutable_item()
->set_type_id((Ydb::Type::PrimitiveTypeId)typeInfo.GetTypeId());
diff --git a/ydb/core/grpc_services/rpc_load_rows.cpp b/ydb/core/grpc_services/rpc_load_rows.cpp
index 8092d80428e..3e76492491f 100644
--- a/ydb/core/grpc_services/rpc_load_rows.cpp
+++ b/ydb/core/grpc_services/rpc_load_rows.cpp
@@ -92,7 +92,7 @@ bool CheckValueData(NScheme::TTypeInfo type, const TCell& cell, TString& err) {
}
if (!ok) {
- err = Sprintf("Invalid %s value", NScheme::TypeName(type));
+ err = Sprintf("Invalid %s value", NScheme::TypeName(type).c_str());
}
return ok;
@@ -195,7 +195,7 @@ public:
{}
private:
- static bool CellFromProtoVal(NScheme::TTypeInfo type, const Ydb::Value* vp,
+ static bool CellFromProtoVal(NScheme::TTypeInfo type, i32 typmod, const Ydb::Value* vp,
TCell& c, TString& err, TMemoryPool& valueDataPool)
{
if (vp->Hasnull_flag_value()) {
@@ -272,21 +272,53 @@ private:
break;
}
case NScheme::NTypeIds::Pg : {
+ TString binary;
+ bool isText = false;
TString text = val.Gettext_value();
if (!text.empty()) {
+ isText = true;
auto desc = type.GetTypeDesc();
auto id = NPg::PgTypeIdFromTypeDesc(desc);
- auto result = NPg::PgNativeBinaryFromNativeText(text, id);
- if (!result.Error.empty()) {
+ auto res = NPg::PgNativeBinaryFromNativeText(text, id);
+ if (res.Error) {
err = TStringBuilder() << "Invalid text value for "
- << NPg::PgTypeNameFromTypeDesc(desc) << ": " << result.Error;
+ << NPg::PgTypeNameFromTypeDesc(desc) << ": " << *res.Error;
return false;
}
- const auto valueInPool = valueDataPool.AppendString(TStringBuf(result.Str));
- c = TCell(valueInPool.data(), valueInPool.size());
+ binary = res.Str;
} else {
- TString binary = val.Getbytes_value();
- c = TCell(binary.data(), binary.size());
+ binary = val.Getbytes_value();
+ }
+ auto* desc = type.GetTypeDesc();
+ if (typmod != -1 && NPg::TypeDescNeedsCoercion(desc)) {
+ auto res = NPg::PgNativeBinaryCoerce(TStringBuf(binary), desc, typmod);
+ if (res.Error) {
+ err = TStringBuilder() << "Unable to coerce value for "
+ << NPg::PgTypeNameFromTypeDesc(desc) << ": " << *res.Error;
+ return false;
+ }
+ if (res.NewValue) {
+ const auto valueInPool = valueDataPool.AppendString(TStringBuf(*res.NewValue));
+ c = TCell(valueInPool.data(), valueInPool.size());
+ } else if (isText) {
+ const auto valueInPool = valueDataPool.AppendString(TStringBuf(binary));
+ c = TCell(valueInPool.data(), valueInPool.size());
+ } else {
+ c = TCell(binary.data(), binary.size());
+ }
+ } else {
+ auto error = NPg::PgNativeBinaryValidate(TStringBuf(binary), desc);
+ if (error) {
+ err = TStringBuilder() << "Invalid binary value for "
+ << NPg::PgTypeNameFromTypeDesc(desc) << ": " << *error;
+ return false;
+ }
+ if (isText) {
+ const auto valueInPool = valueDataPool.AppendString(TStringBuf(binary));
+ c = TCell(valueInPool.data(), valueInPool.size());
+ } else {
+ c = TCell(binary.data(), binary.size());
+ }
}
break;
}
@@ -311,7 +343,7 @@ private:
return false;
}
cells.push_back({});
- if (!CellFromProtoVal(fd.Type, &proto.Getitems(fd.PositionInStruct), cells.back(), err, valueDataPool)) {
+ if (!CellFromProtoVal(fd.Type, fd.Typmod, &proto.Getitems(fd.PositionInStruct), cells.back(), err, valueDataPool)) {
return false;
}
diff --git a/ydb/core/grpc_services/rpc_log_store.cpp b/ydb/core/grpc_services/rpc_log_store.cpp
index 432a74c9dd0..7c2d62aee92 100644
--- a/ydb/core/grpc_services/rpc_log_store.cpp
+++ b/ydb/core/grpc_services/rpc_log_store.cpp
@@ -95,10 +95,11 @@ bool ConvertSchemaFromPublicToInternal(const Ydb::LogStore::Schema& from, NKikim
auto* col = to.AddColumns();
col->SetName(column.name());
NScheme::TTypeInfo typeInfo;
- if (!ExtractColumnTypeInfo(typeInfo, column.type(), status, error)) {
+ TString typeMod;
+ if (!ExtractColumnTypeInfo(typeInfo, typeMod, column.type(), status, error)) {
return false;
}
- auto typeName = NScheme::TypeName(typeInfo);
+ auto typeName = NScheme::TypeName(typeInfo, typeMod);
col->SetType(typeName);
if (key.count(column.name())) {
col->SetNotNull(true);
diff --git a/ydb/core/grpc_services/rpc_long_tx.cpp b/ydb/core/grpc_services/rpc_long_tx.cpp
index b50d99fe428..230ec01ed0f 100644
--- a/ydb/core/grpc_services/rpc_long_tx.cpp
+++ b/ydb/core/grpc_services/rpc_long_tx.cpp
@@ -37,9 +37,9 @@ std::shared_ptr<arrow::Schema> ExtractArrowSchema(const NKikimrSchemeOp::TColumn
TVector<std::pair<TString, NScheme::TTypeInfo>> columns;
for (auto& col : schema.GetColumns()) {
Y_VERIFY(col.HasTypeId());
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
- columns.emplace_back(col.GetName(), typeInfo);
+ columns.emplace_back(col.GetName(), typeInfoMod.TypeInfo);
}
return NArrow::MakeArrowSchema(columns);
diff --git a/ydb/core/grpc_services/rpc_read_columns.cpp b/ydb/core/grpc_services/rpc_read_columns.cpp
index 892fe134244..c5e53f48863 100644
--- a/ydb/core/grpc_services/rpc_read_columns.cpp
+++ b/ydb/core/grpc_services/rpc_read_columns.cpp
@@ -270,7 +270,7 @@ private:
KeyColumnTypes[ci.second.KeyOrder] = ci.second.PType;
columns.resize(Max<size_t>(columns.size(), ci.second.KeyOrder + 1));
- columns[ci.second.KeyOrder] = {ci.second.Id, ci.second.PType};
+ columns[ci.second.KeyOrder] = {ci.second.Id, ci.second.PType, ci.second.PTypeMod};
}
}
@@ -283,7 +283,7 @@ private:
}
auto ci = entry.Columns.find(id->second);
- columns.push_back({ci->second.Id, ci->second.PType});
+ columns.push_back({ci->second.Id, ci->second.PType, ci->second.PTypeMod});
valueColumnNamesAndTypes.push_back({ci->second.Name, ci->second.PType});
ValueColumnTypes.push_back(ci->second.PType);
diff --git a/ydb/core/kqp/common/kqp_resolve.h b/ydb/core/kqp/common/kqp_resolve.h
index 7d9c3e3b2d3..542e9e03384 100644
--- a/ydb/core/kqp/common/kqp_resolve.h
+++ b/ydb/core/kqp/common/kqp_resolve.h
@@ -24,6 +24,7 @@ public:
struct TColumn {
ui32 Id;
NScheme::TTypeInfo Type;
+ TString TypeMod;
};
struct TTable {
diff --git a/ydb/core/kqp/compute_actor/kqp_scan_compute_actor.cpp b/ydb/core/kqp/compute_actor/kqp_scan_compute_actor.cpp
index 5cc59095c86..aa40b41e95c 100644
--- a/ydb/core/kqp/compute_actor/kqp_scan_compute_actor.cpp
+++ b/ydb/core/kqp/compute_actor/kqp_scan_compute_actor.cpp
@@ -303,7 +303,7 @@ private:
ev->Record.SetLocalPathId(ScanData->TableId.PathId.LocalPathId);
for (auto& column: ScanData->GetColumns()) {
ev->Record.AddColumnTags(column.Tag);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
ev->Record.AddColumnTypes(columnType.TypeId);
if (columnType.TypeInfo) {
*ev->Record.AddColumnTypeInfos() = *columnType.TypeInfo;
diff --git a/ydb/core/kqp/executer_actor/kqp_data_executer.cpp b/ydb/core/kqp/executer_actor/kqp_data_executer.cpp
index 0b5e8cefcab..82c1b23ebe2 100644
--- a/ydb/core/kqp/executer_actor/kqp_data_executer.cpp
+++ b/ydb/core/kqp/executer_actor/kqp_data_executer.cpp
@@ -1555,7 +1555,7 @@ private:
for (auto& column : read.Columns) {
auto* protoColumn = protoReadMeta->AddColumns();
protoColumn->SetId(column.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
protoColumn->SetType(columnType.TypeId);
if (columnType.TypeInfo) {
*protoColumn->MutableTypeInfo() = *columnType.TypeInfo;
@@ -1578,7 +1578,7 @@ private:
auto& protoColumn = *protoColumnWrite.MutableColumn();
protoColumn.SetId(columnWrite.Column.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(columnWrite.Column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(columnWrite.Column.Type, columnWrite.Column.TypeMod);
protoColumn.SetType(columnType.TypeId);
if (columnType.TypeInfo) {
*protoColumn.MutableTypeInfo() = *columnType.TypeInfo;
@@ -1601,7 +1601,7 @@ private:
const auto& tableInfo = TableKeys.GetTable(stageInfo.Meta.TableId);
for (const auto& keyColumnName : tableInfo.KeyColumns) {
const auto& keyColumn = tableInfo.Columns.at(keyColumnName);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(keyColumn.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(keyColumn.Type, keyColumn.TypeMod);
protoTaskMeta.AddKeyColumnTypes(columnType.TypeId);
if (columnType.TypeInfo) {
*protoTaskMeta.AddKeyColumnTypeInfos() = *columnType.TypeInfo;
@@ -1618,7 +1618,7 @@ private:
for (auto& column : task.Meta.Reads->front().Columns) {
auto* protoColumn = protoTaskMeta.AddColumns();
protoColumn->SetId(column.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
protoColumn->SetType(columnType.TypeId);
if (columnType.TypeInfo) {
*protoColumn->MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/kqp/executer_actor/kqp_executer_impl.h b/ydb/core/kqp/executer_actor/kqp_executer_impl.h
index 75f50425cfd..686207b901a 100644
--- a/ydb/core/kqp/executer_actor/kqp_executer_impl.h
+++ b/ydb/core/kqp/executer_actor/kqp_executer_impl.h
@@ -705,7 +705,7 @@ protected:
FillTableMeta(stageInfo, settings.MutableTable());
for (auto& keyColumn : keyTypes) {
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(keyColumn);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(keyColumn, "");
if (columnType.TypeInfo) {
*settings.AddKeyColumnTypeInfos() = *columnType.TypeInfo;
} else {
@@ -717,7 +717,7 @@ protected:
for (auto& column : columns) {
auto* protoColumn = settings.AddColumns();
protoColumn->SetId(column.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
protoColumn->SetType(columnType.TypeId);
if (columnType.TypeInfo) {
*protoColumn->MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/kqp/executer_actor/kqp_scan_executer.cpp b/ydb/core/kqp/executer_actor/kqp_scan_executer.cpp
index a80a87d6f64..2737b45ccf9 100644
--- a/ydb/core/kqp/executer_actor/kqp_scan_executer.cpp
+++ b/ydb/core/kqp/executer_actor/kqp_scan_executer.cpp
@@ -553,7 +553,7 @@ private:
const auto& tableInfo = TableKeys.GetTable(stageInfo.Meta.TableId);
for (const auto& keyColumnName : tableInfo.KeyColumns) {
const auto& keyColumn = tableInfo.Columns.at(keyColumnName);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(keyColumn.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(keyColumn.Type, keyColumn.TypeMod);
protoTaskMeta.AddKeyColumnTypes(columnType.TypeId);
if (columnType.TypeInfo) {
*protoTaskMeta.AddKeyColumnTypeInfos() = *columnType.TypeInfo;
@@ -603,7 +603,7 @@ private:
for (auto columnType : task.Meta.ReadInfo.ResultColumnsTypes) {
auto* protoResultColumn = protoTaskMeta.AddResultColumns();
protoResultColumn->SetId(0);
- auto protoColumnType = NScheme::ProtoColumnTypeFromTypeInfo(columnType);
+ auto protoColumnType = NScheme::ProtoColumnTypeFromTypeInfoMod(columnType, "");
protoResultColumn->SetType(protoColumnType.TypeId);
if (protoColumnType.TypeInfo) {
*protoResultColumn->MutableTypeInfo() = *protoColumnType.TypeInfo;
@@ -624,7 +624,7 @@ private:
for (auto& column : task.Meta.Reads->front().Columns) {
auto* protoColumn = protoTaskMeta.AddColumns();
protoColumn->SetId(column.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, "");
protoColumn->SetType(columnType.TypeId);
if (columnType.TypeInfo) {
*protoColumn->MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/kqp/executer_actor/kqp_tasks_graph.h b/ydb/core/kqp/executer_actor/kqp_tasks_graph.h
index 3a961d1d9b8..860d88bda42 100644
--- a/ydb/core/kqp/executer_actor/kqp_tasks_graph.h
+++ b/ydb/core/kqp/executer_actor/kqp_tasks_graph.h
@@ -107,6 +107,7 @@ struct TTaskMeta {
struct TColumn {
ui32 Id = 0;
NScheme::TTypeInfo Type;
+ TString TypeMod;
TString Name;
};
@@ -180,8 +181,10 @@ TVector<TTaskMeta::TColumn> BuildKqpColumns(const Proto& op, const TKqpTableKeys
for (const auto& column : op.GetColumns()) {
TTaskMeta::TColumn c;
+ const auto& tableColumn = table.Columns.at(column.GetName());
c.Id = column.GetId();
- c.Type = table.Columns.at(column.GetName()).Type;
+ c.Type = tableColumn.Type;
+ c.TypeMod = tableColumn.TypeMod;
c.Name = column.GetName();
columns.emplace_back(std::move(c));
diff --git a/ydb/core/kqp/gateway/kqp_metadata_loader.cpp b/ydb/core/kqp/gateway/kqp_metadata_loader.cpp
index ac5ae77a5c5..adadd1a8577 100644
--- a/ydb/core/kqp/gateway/kqp_metadata_loader.cpp
+++ b/ydb/core/kqp/gateway/kqp_metadata_loader.cpp
@@ -156,12 +156,12 @@ TTableMetadataResult GetLoadTableMetadataResult(const NSchemeCache::TSchemeCache
} else {
Y_VERIFY(columnDesc.PType.GetTypeDesc(), "no pg type descriptor");
Y_VERIFY(!notNull, "pg not null types are not allowed");
- typeName = NPg::PgTypeNameFromTypeDesc(columnDesc.PType.GetTypeDesc());
+ typeName = NPg::PgTypeNameFromTypeDesc(columnDesc.PType.GetTypeDesc(), columnDesc.PTypeMod);
}
tableMeta->Columns.emplace(
columnDesc.Name,
NYql::TKikimrColumnMetadata(
- columnDesc.Name, columnDesc.Id, typeName, notNull, columnDesc.PType
+ columnDesc.Name, columnDesc.Id, typeName, notNull, columnDesc.PType, columnDesc.PTypeMod
)
);
if (columnDesc.KeyOrder >= 0) {
diff --git a/ydb/core/kqp/provider/yql_kikimr_gateway.cpp b/ydb/core/kqp/provider/yql_kikimr_gateway.cpp
index d251aad27e9..5bc3dc8fa24 100644
--- a/ydb/core/kqp/provider/yql_kikimr_gateway.cpp
+++ b/ydb/core/kqp/provider/yql_kikimr_gateway.cpp
@@ -214,8 +214,12 @@ void SetColumnType(Ydb::Type& protoType, const TString& typeName, bool notNull)
auto* typeDesc = NKikimr::NPg::TypeDescFromPgTypeName(typeName);
if (typeDesc) {
Y_VERIFY(!notNull, "It is not allowed to create NOT NULL pg columns");
- auto pg = protoType.mutable_pg_type();
+ auto* pg = protoType.mutable_pg_type();
+ pg->set_type_name(NKikimr::NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_type_modifier(NKikimr::NPg::TypeModFromPgTypeName(typeName));
pg->set_oid(NKikimr::NPg::PgTypeIdFromTypeDesc(typeDesc));
+ pg->set_typlen(0);
+ pg->set_typmod(0);
return;
}
diff --git a/ydb/core/kqp/provider/yql_kikimr_gateway.h b/ydb/core/kqp/provider/yql_kikimr_gateway.h
index b8688ebe175..6145d2c9f75 100644
--- a/ydb/core/kqp/provider/yql_kikimr_gateway.h
+++ b/ydb/core/kqp/provider/yql_kikimr_gateway.h
@@ -182,16 +182,19 @@ struct TKikimrColumnMetadata {
TString Type;
bool NotNull = false;
NKikimr::NScheme::TTypeInfo TypeInfo;
+ TString TypeMod;
TVector<TString> Families;
TKikimrColumnMetadata() = default;
- TKikimrColumnMetadata(const TString& name, ui32 id, const TString& type, bool notNull, NKikimr::NScheme::TTypeInfo typeInfo = {})
+ TKikimrColumnMetadata(const TString& name, ui32 id, const TString& type, bool notNull,
+ NKikimr::NScheme::TTypeInfo typeInfo = {}, const TString& typeMod = {})
: Name(name)
, Id(id)
, Type(type)
, NotNull(notNull)
, TypeInfo(typeInfo)
+ , TypeMod(typeMod)
{}
explicit TKikimrColumnMetadata(const NKikimrKqp::TKqpColumnMetadataProto* message)
@@ -201,8 +204,10 @@ struct TKikimrColumnMetadata {
, NotNull(message->GetNotNull())
, Families(message->GetFamily().begin(), message->GetFamily().end())
{
- TypeInfo = NKikimr::NScheme::TypeInfoFromProtoColumnType(message->GetTypeId(),
+ auto typeInfoMod = NKikimr::NScheme::TypeInfoModFromProtoColumnType(message->GetTypeId(),
message->HasTypeInfo() ? &message->GetTypeInfo() : nullptr);
+ TypeInfo = typeInfoMod.TypeInfo;
+ TypeMod = typeInfoMod.TypeMod;
}
void ToMessage(NKikimrKqp::TKqpColumnMetadataProto* message) const {
@@ -210,7 +215,7 @@ struct TKikimrColumnMetadata {
message->SetId(Id);
message->SetType(Type);
message->SetNotNull(NotNull);
- auto columnType = NKikimr::NScheme::ProtoColumnTypeFromTypeInfo(TypeInfo);
+ auto columnType = NKikimr::NScheme::ProtoColumnTypeFromTypeInfoMod(TypeInfo, TypeMod);
message->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*message->MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/kqp/provider/yql_kikimr_provider.cpp b/ydb/core/kqp/provider/yql_kikimr_provider.cpp
index 47f6e8a122d..763da848c72 100644
--- a/ydb/core/kqp/provider/yql_kikimr_provider.cpp
+++ b/ydb/core/kqp/provider/yql_kikimr_provider.cpp
@@ -176,6 +176,7 @@ bool TKikimrTableDescription::Load(TExprContext& ctx, bool withSystemColumns) {
type = ctx.MakeType<TPgExprType>(NKikimr::NPg::PgTypeIdFromTypeDesc(column.TypeInfo.GetTypeDesc()));
}
}
+
if (!column.NotNull && column.TypeInfo.GetTypeId() != NKikimr::NScheme::NTypeIds::Pg) {
type = ctx.MakeType<TOptionalExprType>(type);
}
diff --git a/ydb/core/kqp/runtime/kqp_compute.h b/ydb/core/kqp/runtime/kqp_compute.h
index ae90fd8e466..b3cfc21d2e6 100644
--- a/ydb/core/kqp/runtime/kqp_compute.h
+++ b/ydb/core/kqp/runtime/kqp_compute.h
@@ -15,6 +15,7 @@ public:
struct TColumn {
NTable::TTag Tag;
NScheme::TTypeInfo Type;
+ TString TypeMod;
};
// used only at then building of a computation graph, to inject taskId in runtime nodes
diff --git a/ydb/core/kqp/runtime/kqp_scan_data.cpp b/ydb/core/kqp/runtime/kqp_scan_data.cpp
index 4ae2eb8b2fb..8205487ad47 100644
--- a/ydb/core/kqp/runtime/kqp_scan_data.cpp
+++ b/ydb/core/kqp/runtime/kqp_scan_data.cpp
@@ -447,8 +447,10 @@ TKqpScanComputeContext::TScanData::TScanData(const NKikimrTxDataShard::TKqpTrans
for (const auto& column : meta.GetColumns()) {
NMiniKQL::TKqpScanComputeContext::TColumn c;
c.Tag = column.GetId();
- c.Type = NScheme::TypeInfoFromProtoColumnType(column.GetType(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(column.GetType(),
column.HasTypeInfo() ? &column.GetTypeInfo() : nullptr);
+ c.Type = typeInfoMod.TypeInfo;
+ c.TypeMod = typeInfoMod.TypeMod;
if (!IsSystemColumn(c.Tag)) {
Columns.emplace_back(std::move(c));
@@ -465,8 +467,10 @@ TKqpScanComputeContext::TScanData::TScanData(const NKikimrTxDataShard::TKqpTrans
for (const auto& resColumn : meta.GetResultColumns()) {
NMiniKQL::TKqpScanComputeContext::TColumn c;
c.Tag = resColumn.GetId();
- c.Type = NScheme::TypeInfoFromProtoColumnType(resColumn.GetType(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(resColumn.GetType(),
resColumn.HasTypeInfo() ? &resColumn.GetTypeInfo() : nullptr);
+ c.Type = typeInfoMod.TypeInfo;
+ c.TypeMod = typeInfoMod.TypeMod;
if (!IsSystemColumn(c.Tag)) {
ResultColumns.emplace_back(std::move(c));
diff --git a/ydb/core/kqp/runtime/kqp_scan_data_ut.cpp b/ydb/core/kqp/runtime/kqp_scan_data_ut.cpp
index aae2d0c669f..90eab85f740 100644
--- a/ydb/core/kqp/runtime/kqp_scan_data_ut.cpp
+++ b/ydb/core/kqp/runtime/kqp_scan_data_ut.cpp
@@ -14,26 +14,26 @@ using TTypeInfo = NScheme::TTypeInfo;
struct TDataRow {
TSmallVec<TKqpComputeContextBase::TColumn> Columns() {
return {
- {0, TTypeInfo(NTypeIds::Bool)},
- {1, TTypeInfo(NTypeIds::Int8)},
- {2, TTypeInfo(NTypeIds::Int16)},
- {3, TTypeInfo(NTypeIds::Int32)},
- {4, TTypeInfo(NTypeIds::Int64)},
- {5, TTypeInfo(NTypeIds::Uint8)},
- {6, TTypeInfo(NTypeIds::Uint16)},
- {7, TTypeInfo(NTypeIds::Uint32)},
- {8, TTypeInfo(NTypeIds::Uint64)},
- {9, TTypeInfo(NTypeIds::Float)},
- {10, TTypeInfo(NTypeIds::Double)},
- {11, TTypeInfo(NTypeIds::String)},
- {12, TTypeInfo(NTypeIds::Utf8)},
- {13, TTypeInfo(NTypeIds::Json)},
- {14, TTypeInfo(NTypeIds::Yson)},
- {15, TTypeInfo(NTypeIds::Date)},
- {16, TTypeInfo(NTypeIds::Datetime)},
- {17, TTypeInfo(NTypeIds::Timestamp)},
- {18, TTypeInfo(NTypeIds::Interval)},
- {19, TTypeInfo(NTypeIds::Decimal)},
+ {0, TTypeInfo(NTypeIds::Bool), ""},
+ {1, TTypeInfo(NTypeIds::Int8), ""},
+ {2, TTypeInfo(NTypeIds::Int16), ""},
+ {3, TTypeInfo(NTypeIds::Int32), ""},
+ {4, TTypeInfo(NTypeIds::Int64), ""},
+ {5, TTypeInfo(NTypeIds::Uint8), ""},
+ {6, TTypeInfo(NTypeIds::Uint16), ""},
+ {7, TTypeInfo(NTypeIds::Uint32), ""},
+ {8, TTypeInfo(NTypeIds::Uint64), ""},
+ {9, TTypeInfo(NTypeIds::Float), ""},
+ {10, TTypeInfo(NTypeIds::Double), ""},
+ {11, TTypeInfo(NTypeIds::String), ""},
+ {12, TTypeInfo(NTypeIds::Utf8), ""},
+ {13, TTypeInfo(NTypeIds::Json), ""},
+ {14, TTypeInfo(NTypeIds::Yson), ""},
+ {15, TTypeInfo(NTypeIds::Date), ""},
+ {16, TTypeInfo(NTypeIds::Datetime), ""},
+ {17, TTypeInfo(NTypeIds::Timestamp), ""},
+ {18, TTypeInfo(NTypeIds::Interval), ""},
+ {19, TTypeInfo(NTypeIds::Decimal), ""},
};
}
diff --git a/ydb/core/kqp/runtime/kqp_stream_lookup_actor.cpp b/ydb/core/kqp/runtime/kqp_stream_lookup_actor.cpp
index e1386cff6f0..95d0908192e 100644
--- a/ydb/core/kqp/runtime/kqp_stream_lookup_actor.cpp
+++ b/ydb/core/kqp/runtime/kqp_stream_lookup_actor.cpp
@@ -43,6 +43,7 @@ public:
keyColumn.GetName(),
keyColumn.GetId(),
NScheme::TTypeInfo{static_cast<NScheme::TTypeId>(keyColumn.GetTypeId())},
+ "",
keyOrder++
}
);
diff --git a/ydb/core/kqp/ut/pg/CMakeLists.darwin.txt b/ydb/core/kqp/ut/pg/CMakeLists.darwin.txt
index 5c0c5568cf8..47c4c850150 100644
--- a/ydb/core/kqp/ut/pg/CMakeLists.darwin.txt
+++ b/ydb/core/kqp/ut/pg/CMakeLists.darwin.txt
@@ -61,7 +61,7 @@ set_yunittest_property(
ydb-core-kqp-ut-pg
PROPERTY
LABELS
- SMALL
+ MEDIUM
)
set_yunittest_property(
TEST
diff --git a/ydb/core/kqp/ut/pg/CMakeLists.linux-aarch64.txt b/ydb/core/kqp/ut/pg/CMakeLists.linux-aarch64.txt
index c1cab438236..3908d66312e 100644
--- a/ydb/core/kqp/ut/pg/CMakeLists.linux-aarch64.txt
+++ b/ydb/core/kqp/ut/pg/CMakeLists.linux-aarch64.txt
@@ -64,7 +64,7 @@ set_yunittest_property(
ydb-core-kqp-ut-pg
PROPERTY
LABELS
- SMALL
+ MEDIUM
)
set_yunittest_property(
TEST
diff --git a/ydb/core/kqp/ut/pg/CMakeLists.linux.txt b/ydb/core/kqp/ut/pg/CMakeLists.linux.txt
index bf122a5ede1..200982bc5b4 100644
--- a/ydb/core/kqp/ut/pg/CMakeLists.linux.txt
+++ b/ydb/core/kqp/ut/pg/CMakeLists.linux.txt
@@ -66,7 +66,7 @@ set_yunittest_property(
ydb-core-kqp-ut-pg
PROPERTY
LABELS
- SMALL
+ MEDIUM
)
set_yunittest_property(
TEST
diff --git a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
index 9c8fbe6266d..3d063c15c09 100644
--- a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
+++ b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
@@ -13,19 +13,17 @@ extern "C" {
namespace {
struct TPgTypeTestSpec {
+ ui32 TypeId;
bool IsKey;
std::function<TString(size_t)> TextIn, TextOut;
- std::function<TString(TString)> ArrayPrint;
- TPgTypeTestSpec() = default;
- TPgTypeTestSpec(
- bool isKey,
- std::function<TString(size_t)> in,
- std::function<TString(size_t)> out,
- std::function<TString(TString)> print = [] (auto s) { return Sprintf("{%s,%s}", s.c_str(), s.c_str()); })
- : IsKey(isKey)
- , TextIn(in)
- , TextOut(out)
- , ArrayPrint(print) {}
+ std::function<TString(TString)> ArrayPrint = [] (auto s) { return Sprintf("{%s,%s}", s.c_str(), s.c_str()); };
+ };
+
+ struct TPgTypeCoercionTestSpec {
+ ui32 TypeId;
+ TString TypeMod;
+ bool ShouldPass;
+ std::function<TString()> TextIn, TextOut;
};
}
@@ -35,8 +33,9 @@ namespace NKqp {
using namespace NYdb;
using namespace NYdb::NTable;
-NYdb::NScripting::TExecuteYqlResult
-ExecutePgSelect(NKikimr::NKqp::TKikimrRunner& kikimr, const TString& tableName) {
+NYdb::NScripting::TExecuteYqlResult ExecutePgSelect(
+ NKikimr::NKqp::TKikimrRunner& kikimr, const TString& tableName)
+{
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
auto result = client.ExecuteYqlScript(
TStringBuilder() << R"(
@@ -44,23 +43,22 @@ ExecutePgSelect(NKikimr::NKqp::TKikimrRunner& kikimr, const TString& tableName)
SELECT * FROM ")"
<< tableName << "\""
).GetValueSync();
- UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
return result;
}
void ExecutePgInsert(
NKikimr::NKqp::TKikimrRunner& kikimr,
const TString& tableName,
- ui32 id,
- const TPgTypeTestSpec& spec
-) {
+ const TPgTypeTestSpec& spec)
+{
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
- auto valType = NYql::NPg::LookupType(id).Name;
+ auto valType = NYql::NPg::LookupType(spec.TypeId).Name;
auto keyType = (spec.IsKey) ? valType : "int2";
- if (id == BITOID) {
+ if (spec.TypeId == BITOID) {
valType.append("(4)");
}
- for (size_t i = 0; i < ((id == BOOLOID) ? 2 : 3); i++) {
+ for (size_t i = 0; i < ((spec.TypeId == BOOLOID) ? 2 : 3); i++) {
auto keyIn = (spec.IsKey) ? spec.TextIn(i) : ToString(i);
TString req = Sprintf("\
--!syntax_pg\n\
@@ -69,23 +67,22 @@ void ExecutePgInsert(
)", tableName.Data(), keyIn.Data(), keyType.Data(), spec.TextIn(i).Data(), valType.Data());
Cerr << req << Endl;
auto result = client.ExecuteYqlScript(req).GetValueSync();
- UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
}
}
void ExecutePgArrayInsert(
NKikimr::NKqp::TKikimrRunner& kikimr,
const TString& tableName,
- ui32 id,
- const TPgTypeTestSpec& spec
-) {
+ const TPgTypeTestSpec& spec)
+{
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
- auto valType = NYql::NPg::LookupType(id).Name;
- if (id == BITOID) {
+ auto valType = NYql::NPg::LookupType(spec.TypeId).Name;
+ if (spec.TypeId == BITOID) {
valType.append("(4)");
}
- for (size_t i = 0; i < ((id == BOOLOID) ? 2 : 3); i++) {
- auto keyEntry = Sprintf("'%d'::int2", i);
+ for (size_t i = 0; i < ((spec.TypeId == BOOLOID) ? 2 : 3); i++) {
+ auto keyEntry = Sprintf("'%u'::int2", i);
auto valueEntry = Sprintf(
"ARRAY ['%s'::%s, '%s'::%s]",
spec.TextIn(i).Data(),
@@ -100,7 +97,7 @@ void ExecutePgArrayInsert(
);", tableName.Data(), keyEntry.Data(), valueEntry.Data());
Cerr << req << Endl;
auto result = client.ExecuteYqlScript(req).GetValueSync();
- UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
}
}
@@ -125,293 +122,540 @@ void ValidatePgYqlResult(const NYdb::NScripting::TExecuteYqlResult& result, cons
Y_UNIT_TEST_SUITE(KqpPg) {
- auto makePgType = [] (ui32 oid, i32 typlen = -1) { return TPgType(oid, typlen, -1); };
-
- TMap<
- ui32,
- TPgTypeTestSpec
- > typeSpecs ={
- { BOOLOID, {
+ TVector<TPgTypeTestSpec> typeSpecs = {
+ {
+ BOOLOID,
true,
[] (auto i) { return TString(i ? "true" : "false"); },
[] (auto i) { return TString(i ? "t" : "f"); }
- }
},
- { CHAROID, {
+ {
+ CHAROID,
true,
[] (auto i) { return Sprintf("%c", (char)(i + '0')); },
[] (auto i) { return Sprintf("%c", (char)(i + '0')); }
- }
},
- { INT2OID, {
+ {
+ INT2OID,
true,
[] (auto i) { return Sprintf("%u", i); },
[] (auto i) { return Sprintf("%u", i); }
- }
},
- { INT4OID, {
+ {
+ INT4OID,
true,
[] (auto i) { return Sprintf("%u", i); },
[] (auto i) { return Sprintf("%u", i); }
- }
},
- { INT8OID, {
+ {
+ INT8OID,
true,
[] (auto i) { return Sprintf("%u", i); },
[] (auto i) { return Sprintf("%u", i); }
- }
},
- { FLOAT4OID, {
+ {
+ FLOAT4OID,
true,
[] (auto i) { return Sprintf("%g", i + 0.5f); },
[] (auto i) { return Sprintf("%g", i + 0.5f); }
- }
},
- { FLOAT8OID, {
+ {
+ FLOAT8OID,
true,
[] (auto i) { return Sprintf("%lg", i + 0.5); },
[] (auto i) { return Sprintf("%lg", i + 0.5); }
- }
},
- { TEXTOID, {
+ {
+ TEXTOID,
true,
[] (auto i) { return Sprintf("text %u", i); },
[] (auto i) { return Sprintf("text %u", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { BPCHAROID, {
+ {
+ BPCHAROID,
true,
[] (auto i) { return Sprintf("bpchar %u", i); },
[] (auto i) { return Sprintf("bpchar %u", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { VARCHAROID, {
+ {
+ VARCHAROID,
false,
[] (auto i) { return Sprintf("varchar %u", i); },
[] (auto i) { return Sprintf("varchar %u", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { NAMEOID, {
+ {
+ NAMEOID,
true,
[] (auto i) { return Sprintf("name %u", i); },
[] (auto i) { return Sprintf("name %u", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { NUMERICOID, {
+ {
+ NUMERICOID,
true,
[] (auto i) { return Sprintf("%lg", i + 0.12345); },
[] (auto i) { return Sprintf("%lg", i + 0.12345); }
- }
},
- { MONEYOID, {
- true,
+ {
+ MONEYOID,
+ false, // no HashProcId
[] (auto i) { return Sprintf("%lg", i + i / 100.); },
[] (auto i) { return Sprintf("$%.2lf", i + i / 100.); }
- }
},
- { DATEOID, {
+ {
+ DATEOID,
true,
[] (auto i) { return Sprintf("1970-01-%02u", i + 1); },
[] (auto i) { return Sprintf("1970-01-%02u", i + 1); }
- }
},
- { TIMEOID, {
+ {
+ TIMEOID,
true,
[] (auto i) { return Sprintf("%02u:01:02.345", i); },
[] (auto i) { return Sprintf("%02u:01:02.345", i); }
- }
},
- { TIMESTAMPOID, {
+ {
+ TIMESTAMPOID,
true,
[] (auto i) { return Sprintf("1970-01-01 %02u:01:02.345", i); },
[] (auto i) { return Sprintf("1970-01-01 %02u:01:02.345", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { TIMETZOID, {
+ {
+ TIMETZOID,
true,
[] (auto i) { return Sprintf("%02u:01:02.345-03", i); },
[] (auto i) { return Sprintf("%02u:01:02.345-03", i); }
- }
},
- { TIMESTAMPTZOID, {
+ {
+ TIMESTAMPTZOID,
true,
[] (auto i) { return Sprintf("1970-01-01 %02u:01:02.345 -3:00", i); },
[] (auto i) { return Sprintf("1970-01-01 %02u:01:02.345+00", i + 3); }, // TODO: investigate
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { INTERVALOID, {
+ {
+ INTERVALOID,
true,
[] (auto i) { return Sprintf("P01-02-03T04:05:%02u", i); },
[] (auto i) { return Sprintf("1 year 2 mons 3 days 04:05:%02u", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { BITOID, {
- true,
+ {
+ BITOID,
+ false, // no HashProcId
[] (auto i) { return Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'); },
[] (auto i) { return Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'); }
- }
},
- { VARBITOID, {
- true,
+ {
+ VARBITOID,
+ false, // no HashProcId
[] (auto i) { return Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'); },
[] (auto i) { return Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'); }
- }
},
- { POINTOID, {
+ {
+ POINTOID,
false,
[] (auto i) { return Sprintf("(10, %u)", i); },
[] (auto i) { return Sprintf("(10,%u)", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { LINEOID, {
+ {
+ LINEOID,
false,
[] (auto i) { return Sprintf("{1, 2, %u}", i); },
[] (auto i) { return Sprintf("{1,2,%u}", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { LSEGOID, {
+ {
+ LSEGOID,
false,
[] (auto i) { return Sprintf("[(0, 0), (1, %u)]", i); },
[] (auto i) { return Sprintf("[(0,0),(1,%u)]", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { BOXOID, {
+ {
+ BOXOID,
false,
[] (auto i) { return Sprintf("(1, %u), (0, 0)", i + 1); },
[] (auto i) { return Sprintf("(1,%u),(0,0)", i + 1); },
[] (auto s) { return Sprintf("{%s;%s}", s.c_str(), s.c_str()); }
- }
},
- { PATHOID, {
+ {
+ PATHOID,
false,
[] (auto i) { return Sprintf("((0, 1), (2, 3), (4, %u))", i); },
[] (auto i) { return Sprintf("((0,1),(2,3),(4,%u))", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { POLYGONOID, {
+ {
+ POLYGONOID,
false,
[] (auto i) { return Sprintf("((0, 1), (2, 3), (4, %u))", i); },
[] (auto i) { return Sprintf("((0,1),(2,3),(4,%u))", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { CIRCLEOID, {
+ {
+ CIRCLEOID,
false,
[] (auto i) { return Sprintf("<(0, 1), %u>", i); },
[] (auto i) { return Sprintf("<(0,1),%u>", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { INETOID, {
+ {
+ INETOID,
false,
[] (auto i) { return Sprintf("128.%u.0.0/16", i); },
[] (auto i) { return Sprintf("128.%u.0.0/16", i); }
- }
},
- { CIDROID, {
+ {
+ CIDROID,
false,
[] (auto i) { return Sprintf("128.%u.0.0/16", i); },
[] (auto i) { return Sprintf("128.%u.0.0/16", i); }
- }
},
- { MACADDROID, {
+ {
+ MACADDROID,
false,
[] (auto i) { return Sprintf("08:00:2b:01:02:%02u", i); },
[] (auto i) { return Sprintf("08:00:2b:01:02:%02u", i); }
- }
},
- { MACADDR8OID, {
+ {
+ MACADDR8OID,
false,
[] (auto i) { return Sprintf("08:00:2b:01:02:03:04:%02u", i); },
[] (auto i) { return Sprintf("08:00:2b:01:02:03:04:%02u", i); }
- }
},
- { UUIDOID, {
+ {
+ UUIDOID,
false,
[] (auto i) { return Sprintf("00000000-0000-0000-0000-0000000000%02u", i); },
[] (auto i) { return Sprintf("00000000-0000-0000-0000-0000000000%02u", i); }
- }
},
- { JSONOID, {
+ {
+ JSONOID,
false,
[] (auto i) { return Sprintf("[%u]", i); },
[] (auto i) { return Sprintf("[%u]", i); }
- }
},
- { JSONBOID, {
+ {
+ JSONBOID,
false,
[] (auto i) { return Sprintf("[%u]", i); },
[] (auto i) { return Sprintf("[%u]", i); }
- }
},
- { JSONPATHOID, {
+ {
+ JSONPATHOID,
false,
[] (auto i) { return Sprintf("$[%u]", i); },
[] (auto i) { return Sprintf("$[%u]", i); }
- }
},
- { XMLOID, {
+ {
+ XMLOID,
false,
[] (auto i) { return Sprintf("<a>%u</a>", i); },
[] (auto i) { return Sprintf("<a>%u</a>", i); }
- }
},
- { TSQUERYOID, {
+ {
+ TSQUERYOID,
false,
[] (auto i) { return Sprintf("a&b%u", i); },
[] (auto i) { return Sprintf("'a' & 'b%u'", i); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { TSVECTOROID, {
+ {
+ TSVECTOROID,
false,
[] (auto i) { return Sprintf("a:1 b:%u", i + 2); },
[] (auto i) { return Sprintf("'a':1 'b':%u", i + 2); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
},
- { INT2VECTOROID, {
+ {
+ INT2VECTOROID,
false,
[] (auto i) { return Sprintf("%u %u %u", i, i + 1, i + 2); },
[] (auto i) { return Sprintf("%u %u %u", i, i + 1, i + 2); },
[] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); }
- }
}
};
+ TPgTypeTestSpec typeByteaSpec{
+ BYTEAOID,
+ true,
+ [] (auto i) { return Sprintf("bytea %u", i); },
+ [] (auto i) { return Sprintf("\\x627974656120%x", i + 48); }
+ };
+
+ TPgTypeTestSpec typeByteaArraySpec{
+ BYTEAARRAYOID,
+ true,
+ [] (auto i) { return Sprintf("{a%u, b%u}", i, i + 10); },
+ [] (auto i) { return Sprintf("{\"\\\\x61%x\",\"\\\\x6231%x\"}", i + 48, i + 48); }
+ };
+
+
+#define SUCCESS true
+#define FAIL false
+
+ TVector<TPgTypeCoercionTestSpec> typeCoercionSpecs = {
+ {
+ BPCHAROID, "2",
+ FAIL,
+ [] () { return TString("abcd"); },
+ [] () { return TString(""); }
+ },
+ {
+ BPCHAROID, "4",
+ SUCCESS,
+ [] () { return TString("abcd"); },
+ [] () { return TString("abcd"); }
+ },
+ {
+ BPCHAROID, "6",
+ SUCCESS,
+ [] () { return TString("abcd"); },
+ [] () { return TString("abcd "); }
+ },
+
+ {
+ VARCHAROID, "2",
+ FAIL,
+ [] () { return TString("abcd"); },
+ [] () { return TString(""); }
+ },
+ {
+ VARCHAROID, "4",
+ SUCCESS,
+ [] () { return TString("abcd"); },
+ [] () { return TString("abcd"); }
+ },
+ {
+ VARCHAROID, "6",
+ SUCCESS,
+ [] () { return TString("abcd"); },
+ [] () { return TString("abcd"); }
+ },
+
+ {
+ BITOID, "2",
+ FAIL,
+ [] () { return TString("1111"); },
+ [] () { return TString(""); }
+ },
+ {
+ BITOID, "4",
+ SUCCESS,
+ [] () { return TString("1111"); },
+ [] () { return TString("1111"); }
+ },
+ {
+ BITOID, "6",
+ FAIL,
+ [] () { return TString("1111"); },
+ [] () { return TString(""); }
+ },
+
+ {
+ VARBITOID, "2",
+ FAIL,
+ [] () { return TString("1111"); },
+ [] () { return TString(""); }
+ },
+ {
+ VARBITOID, "4",
+ SUCCESS,
+ [] () { return TString("1111"); },
+ [] () { return TString("1111"); }
+ },
+ {
+ VARBITOID, "6",
+ SUCCESS,
+ [] () { return TString("1111"); },
+ [] () { return TString("1111"); }
+ },
+
+ {
+ NUMERICOID, "2",
+ FAIL,
+ [] () { return TString("9999"); },
+ [] () { return TString(""); }
+ },
+ {
+ NUMERICOID, "4",
+ SUCCESS,
+ [] () { return TString("9999.1234"); },
+ [] () { return TString("9999"); }
+ },
+ {
+ NUMERICOID, "4",
+ SUCCESS,
+ [] () { return TString("9999"); },
+ [] () { return TString("9999"); }
+ },
+ {
+ NUMERICOID, "6",
+ SUCCESS,
+ [] () { return TString("9999"); },
+ [] () { return TString("9999"); }
+ },
+ {
+ NUMERICOID, "20,2",
+ SUCCESS,
+ [] () { return TString("99.1234"); },
+ [] () { return TString("99.12"); }
+ },
+ {
+ NUMERICOID, "20,4",
+ SUCCESS,
+ [] () { return TString("99.1234"); },
+ [] () { return TString("99.1234"); }
+ },
+ {
+ NUMERICOID, "20,6",
+ SUCCESS,
+ [] () { return TString("99.1234"); },
+ [] () { return TString("99.123400"); }
+ },
+
+ {
+ TIMEOID, "2",
+ SUCCESS,
+ [] () { return TString("01:02:03.1234"); },
+ [] () { return TString("01:02:03.12"); }
+ },
+ {
+ TIMEOID, "4",
+ SUCCESS,
+ [] () { return TString("01:02:03.1234"); },
+ [] () { return TString("01:02:03.1234"); }
+ },
+ {
+ TIMEOID, "6",
+ SUCCESS,
+ [] () { return TString("01:02:03.1234"); },
+ [] () { return TString("01:02:03.1234"); }
+ },
+
+ {
+ TIMETZOID, "2",
+ SUCCESS,
+ [] () { return TString("01:02:03.1234+00"); },
+ [] () { return TString("01:02:03.12+00"); }
+ },
+ {
+ TIMETZOID, "4",
+ SUCCESS,
+ [] () { return TString("01:02:03.1234+00"); },
+ [] () { return TString("01:02:03.1234+00"); }
+ },
+ {
+ TIMETZOID, "6",
+ SUCCESS,
+ [] () { return TString("01:02:03.1234+00"); },
+ [] () { return TString("01:02:03.1234+00"); }
+ },
+
+ {
+ TIMESTAMPOID, "2",
+ SUCCESS,
+ [] () { return TString("2001-01-01 01:02:03.1234"); },
+ [] () { return TString("2001-01-01 01:02:03.12"); }
+ },
+ {
+ TIMESTAMPOID, "4",
+ SUCCESS,
+ [] () { return TString("2001-01-01 01:02:03.1234"); },
+ [] () { return TString("2001-01-01 01:02:03.1234"); }
+ },
+ {
+ TIMESTAMPOID, "6",
+ SUCCESS,
+ [] () { return TString("2001-01-01 01:02:03.1234"); },
+ [] () { return TString("2001-01-01 01:02:03.1234"); }
+ },
+
+ {
+ TIMESTAMPTZOID, "2",
+ SUCCESS,
+ [] () { return TString("2001-01-01 01:02:03.1234+00"); },
+ [] () { return TString("2001-01-01 01:02:03.12+00"); }
+ },
+ {
+ TIMESTAMPTZOID, "4",
+ SUCCESS,
+ [] () { return TString("2001-01-01 01:02:03.1234+00"); },
+ [] () { return TString("2001-01-01 01:02:03.1234+00"); }
+ },
+ {
+ TIMESTAMPTZOID, "6",
+ SUCCESS,
+ [] () { return TString("2001-01-01 01:02:03.1234+00"); },
+ [] () { return TString("2001-01-01 01:02:03.1234+00"); }
+ },
+
+ {
+ INTERVALOID, "day",
+ SUCCESS,
+ [] () { return TString("100 01:02:03.1234"); },
+ [] () { return TString("100 days"); }
+ },
+ {
+ INTERVALOID, "day to minute",
+ SUCCESS,
+ [] () { return TString("100 01:02:03.1234"); },
+ [] () { return TString("100 days 01:02:00"); }
+ },
+ {
+ INTERVALOID, "day to second,2",
+ SUCCESS,
+ [] () { return TString("100 01:02:03.1234"); },
+ [] () { return TString("100 days 01:02:03.12"); }
+ },
+ {
+ INTERVALOID, "day to second,6",
+ SUCCESS,
+ [] () { return TString("100 01:02:03.1234"); },
+ [] () { return TString("100 days 01:02:03.1234"); }
+ },
+ {
+ INTERVALOID, "day to second,6",
+ SUCCESS,
+ [] () { return TString("100 01:02:03.1234"); },
+ [] () { return TString("100 days 01:02:03.1234"); }
+ },
+ };
+
+#undef SUCCESS
+#undef FAIL
+
auto createTable = [] (
NYdb::NTable::TTableClient& db,
NYdb::NTable::TSession& session,
- ui32 id,
+ ui32 typeId,
bool isKey,
bool isText,
std::function<TString(size_t)> textIn,
TString setTableName = "",
ui16 rowCount = 10,
- TVector <TString> colNames = {"key", "value"}
+ TVector<TString> colNames = {"key", "value"}
) {
+ auto* typeDesc = NPg::TypeDescFromPgTypeId(typeId);
+ auto typeName = NPg::PgTypeNameFromTypeDesc(typeDesc);
+
TTableBuilder builder;
if (isKey) {
- builder.AddNullableColumn(colNames[0], makePgType(id));
+ builder.AddNullableColumn(colNames[0], TPgType(typeName));
} else {
- builder.AddNullableColumn(colNames[0], makePgType(INT2OID));
+ builder.AddNullableColumn(colNames[0], TPgType("pgint2"));
}
- builder.AddNullableColumn(colNames[1], makePgType(id));
+ builder.AddNullableColumn(colNames[1], TPgType(typeName));
builder.SetPrimaryKeyColumn(colNames[0]);
auto tableName = (setTableName.empty()) ?
- Sprintf("/Root/Pg%u_%s", id, isText ? "t" : "b") : setTableName;
+ Sprintf("/Root/Pg%u_%s", typeId, isText ? "t" : "b") : setTableName;
auto result = session.CreateTable(tableName, builder.Build()).GetValueSync();
UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
@@ -419,20 +663,20 @@ Y_UNIT_TEST_SUITE(KqpPg) {
NYdb::TValueBuilder rows;
rows.BeginList();
for (size_t i = 0; i < rowCount; ++i) {
- auto str = isText ? textIn(i) : NPg::PgNativeBinaryFromNativeText(textIn(i), id).Str;
+ auto str = isText ? textIn(i) : NPg::PgNativeBinaryFromNativeText(textIn(i), typeId).Str;
auto mode = isText ? TPgValue::VK_TEXT : TPgValue::VK_BINARY;
if (isKey) {
rows.AddListItem()
.BeginStruct()
- .AddMember(colNames[0]).Pg(TPgValue(mode, str, makePgType(id)))
- .AddMember(colNames[1]).Pg(TPgValue(mode, str, makePgType(id)))
+ .AddMember(colNames[0]).Pg(TPgValue(mode, str, TPgType(typeName)))
+ .AddMember(colNames[1]).Pg(TPgValue(mode, str, TPgType(typeName)))
.EndStruct();
} else {
auto int2Str = NPg::PgNativeBinaryFromNativeText(Sprintf("%u", i), INT2OID).Str;
rows.AddListItem()
.BeginStruct()
- .AddMember(colNames[0]).Pg(TPgValue(TPgValue::VK_BINARY, int2Str, makePgType(INT2OID)))
- .AddMember(colNames[1]).Pg(TPgValue(mode, str, makePgType(id)))
+ .AddMember(colNames[0]).Pg(TPgValue(TPgValue::VK_BINARY, int2Str, TPgType("pgint2")))
+ .AddMember(colNames[1]).Pg(TPgValue(mode, str, TPgType(typeName)))
.EndStruct();
}
}
@@ -450,16 +694,71 @@ Y_UNIT_TEST_SUITE(KqpPg) {
return tableName;
};
+ auto createCoercionTable = [] (
+ NYdb::NTable::TTableClient& db,
+ NYdb::NTable::TSession& session,
+ ui32 typeId,
+ const TString& typeMod,
+ std::function<TString()> textIn,
+ size_t rowCount = 1
+ ) {
+ auto* typeDesc = NPg::TypeDescFromPgTypeId(typeId);
+ auto typeName = NPg::PgTypeNameFromTypeDesc(typeDesc);
+
+ TTableBuilder builder;
+ builder.AddNullableColumn("key", TPgType("pgint2"));
+ builder.AddNullableColumn("value", TPgType(typeName, typeMod));
+ builder.SetPrimaryKeyColumn("key");
+
+ auto paramsHash = THash<TString>()(typeMod);
+ auto tableName = Sprintf("/Root/Coerce_%s_%" PRIu64, typeName.c_str(), paramsHash);
+ auto createResult = session.CreateTable(tableName, builder.Build()).GetValueSync();
+ UNIT_ASSERT_C(createResult.IsSuccess(), createResult.GetIssues().ToString());
+
+ auto describeResult = session.DescribeTable(tableName).GetValueSync();
+ UNIT_ASSERT_C(describeResult.IsSuccess(), describeResult.GetIssues().ToString());
+ auto tableColumns = describeResult.GetTableDescription().GetTableColumns();
+ for (const auto& column : tableColumns) {
+ const auto& name = column.Name;
+ const auto& type = column.Type;
+ if (name == "value") {
+ TTypeParser parser(type);
+ auto pgType = parser.GetPg();
+ UNIT_ASSERT(pgType.TypeName == typeName);
+ UNIT_ASSERT(pgType.TypeModifier == typeMod);
+ }
+ }
+
+ NYdb::TValueBuilder rows;
+ rows.BeginList();
+ for (size_t i = 0; i < rowCount; ++i) {
+ auto str = NPg::PgNativeBinaryFromNativeText(textIn(), typeId).Str;
+ auto int2Str = NPg::PgNativeBinaryFromNativeText(Sprintf("%u", i), INT2OID).Str;
+ rows.AddListItem()
+ .BeginStruct()
+ .AddMember("key").Pg(TPgValue(TPgValue::VK_BINARY, int2Str, TPgType("pgint2")))
+ .AddMember("value").Pg(TPgValue(TPgValue::VK_BINARY, str, TPgType(typeName, typeMod)))
+ .EndStruct();
+ }
+ rows.EndList();
+
+ auto upsertResult = db.BulkUpsert(tableName, rows.Build()).GetValueSync();
+ if (!upsertResult.IsSuccess()) {
+ Cerr << upsertResult.GetIssues().ToString() << Endl;
+ return std::make_pair(tableName, false);
+ }
+
+ return std::make_pair(tableName, true);
+ };
+
+
Y_UNIT_TEST(CreateTableBulkUpsertAndRead) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
- auto testSingleType = [&kikimr] (ui32 id, bool isKey, bool isText,
- std::function<TString(size_t)> textIn,
- std::function<TString(size_t)> textOut)
- {
+ auto testSingleType = [&kikimr] (const TPgTypeTestSpec& spec, bool isText) {
auto db = kikimr.GetTableClient();
auto session = db.CreateSession().GetValueSync().GetSession();
- auto tableName = createTable(db, session, id, isKey, isText, textIn);
+ auto tableName = createTable(db, session, spec.TypeId, spec.IsKey, isText, spec.TextIn);
auto readSettings = TReadTableSettings()
.AppendColumns("key")
@@ -479,15 +778,15 @@ Y_UNIT_TEST_SUITE(KqpPg) {
auto resultSet = part.ExtractPart();
TResultSetParser parser(resultSet);
for (size_t i = 0; parser.TryNextRow(); ++i) {
- auto check = [&parser, &id, &i] (const TString& column, const TString& expected) {
+ auto check = [&parser, &spec, &i] (const TString& column, const TString& expected) {
auto& c = parser.ColumnParser(column);
- auto result = NPg::PgNativeTextFromNativeBinary(c.GetPg().Content_, id);
- UNIT_ASSERT_C(result.Error.empty(), result.Error);
+ auto result = NPg::PgNativeTextFromNativeBinary(c.GetPg().Content_, spec.TypeId);
+ UNIT_ASSERT_C(!result.Error, *result.Error);
UNIT_ASSERT_VALUES_EQUAL(expected, result.Str);
Cerr << expected << Endl;
};
- auto expected = textOut(i);
- if (isKey) {
+ auto expected = spec.TextOut(i);
+ if (spec.IsKey) {
check("key", expected);
}
check("value", expected);
@@ -497,55 +796,94 @@ Y_UNIT_TEST_SUITE(KqpPg) {
session.Close().GetValueSync();
};
- auto testType = [&] (ui32 id, const TPgTypeTestSpec& typeSpec)
- {
- testSingleType(id, typeSpec.IsKey, false, typeSpec.TextIn, typeSpec.TextOut);
- testSingleType(id, typeSpec.IsKey, true, typeSpec.TextIn, typeSpec.TextOut);
-
- auto arrayId = NYql::NPg::LookupType(id).ArrayTypeId;
-
- auto textInArray = [&typeSpec] (auto i) {
- auto str = typeSpec.TextIn(i);
- return typeSpec.ArrayPrint(str);
+ auto testType = [&] (const TPgTypeTestSpec& spec) {
+ auto textInArray = [&spec] (auto i) {
+ auto str = spec.TextIn(i);
+ return spec.ArrayPrint(str);
};
- auto textOutArray = [&typeSpec] (auto i) {
- auto str = typeSpec.TextOut(i);
- return typeSpec.ArrayPrint(str);
+ auto textOutArray = [&spec] (auto i) {
+ auto str = spec.TextOut(i);
+ return spec.ArrayPrint(str);
};
- testSingleType(arrayId, typeSpec.IsKey, false, textInArray, textOutArray);
- testSingleType(arrayId, typeSpec.IsKey, true, textInArray, textOutArray);
+ auto arrayTypeId = NYql::NPg::LookupType(spec.TypeId).ArrayTypeId;
+ TPgTypeTestSpec arraySpec{arrayTypeId, spec.IsKey, textInArray, textOutArray};
+
+ testSingleType(spec, false);
+ testSingleType(spec, true);
+ testSingleType(arraySpec, false);
+ testSingleType(arraySpec, true);
};
auto testByteaType = [&] () {
- testSingleType(BYTEAOID, true, false,
- [] (auto i) { return Sprintf("bytea %u", i); },
- [] (auto i) { return Sprintf("\\x627974656120%x", i + 48); });
-
- testSingleType(BYTEAOID, true, true,
- [] (auto i) { return Sprintf("bytea %u", i); },
- [] (auto i) { return Sprintf("\\x627974656120%x", i + 48); });
-
- testSingleType(BYTEAARRAYOID, true, false,
- [] (auto i) { return Sprintf("{a%u, b%u}", i, i + 10); },
- [] (auto i) { return Sprintf("{\"\\\\x61%x\",\"\\\\x6231%x\"}", i + 48, i + 48); });
-
- testSingleType(BYTEAARRAYOID, true, true,
- [] (auto i) { return Sprintf("{a%u, b%u}", i, i + 10); },
- [] (auto i) { return Sprintf("{\"\\\\x61%x\",\"\\\\x6231%x\"}", i + 48, i + 48); });
+ testSingleType(typeByteaSpec, false);
+ testSingleType(typeByteaSpec, true);
+ testSingleType(typeByteaArraySpec, false);
+ testSingleType(typeByteaArraySpec, true);
};
testByteaType();
- for (const auto& [oid, spec] : typeSpecs) {
- testType(oid, spec);
+ for (const auto& spec : typeSpecs) {
+ testType(spec);
}
// TODO: varchar as a key
// TODO: native range/multirange types (use get_range_io_data())
}
+ Y_UNIT_TEST(TypeCoercionBulkUpsert) {
+ TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
+
+ auto testType = [&kikimr] (const TPgTypeCoercionTestSpec& spec) {
+ auto db = kikimr.GetTableClient();
+ auto session = db.CreateSession().GetValueSync().GetSession();
+
+ TString tableName;
+ bool success;
+ std::tie(tableName, success) = createCoercionTable(db, session, spec.TypeId, spec.TypeMod, spec.TextIn);
+
+ UNIT_ASSERT_VALUES_EQUAL(success, spec.ShouldPass);
+ if (!success) {
+ return;
+ }
+
+ auto readSettings = TReadTableSettings()
+ .AppendColumns("key")
+ .AppendColumns("value");
+
+ auto it = session.ReadTable(tableName, readSettings).GetValueSync();
+ UNIT_ASSERT_C(it.IsSuccess(), it.GetIssues().ToString());
+
+ bool eos = false;
+ while (!eos) {
+ auto part = it.ReadNext().ExtractValueSync();
+ if (!part.IsSuccess()) {
+ eos = true;
+ Y_ENSURE(part.EOS());
+ continue;
+ }
+ auto resultSet = part.ExtractPart();
+ TResultSetParser parser(resultSet);
+ for (size_t i = 0; parser.TryNextRow(); ++i) {
+ auto expected = spec.TextOut();
+ auto& c = parser.ColumnParser("value");
+ auto result = NPg::PgNativeTextFromNativeBinary(c.GetPg().Content_, spec.TypeId);
+ UNIT_ASSERT_C(!result.Error, *result.Error);
+ UNIT_ASSERT_VALUES_EQUAL(expected, result.Str);
+ Cerr << expected << Endl;
+ }
+ }
+
+ session.Close().GetValueSync();
+ };
+
+ for (const auto& spec : typeCoercionSpecs) {
+ testType(spec);
+ }
+ }
+
Y_UNIT_TEST(EmptyQuery) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
@@ -554,7 +892,7 @@ Y_UNIT_TEST_SUITE(KqpPg) {
--!syntax_pg
)").GetValueSync();
- UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
Y_ENSURE(result.GetResultSets().empty());
}
@@ -571,7 +909,7 @@ Y_UNIT_TEST_SUITE(KqpPg) {
) AS t (int8, varchar);
)").GetValueSync();
- UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
CompareYson(R"([
["1";"one"];
@@ -582,55 +920,46 @@ Y_UNIT_TEST_SUITE(KqpPg) {
Y_UNIT_TEST(TableSelect) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
- auto testSingleType = [&kikimr] (ui32 id, const TPgTypeTestSpec& spec)
- {
+
+ auto testSingleType = [&kikimr] (const TPgTypeTestSpec& spec) {
auto db = kikimr.GetTableClient();
auto session = db.CreateSession().GetValueSync().GetSession();
- auto tableName = createTable(db, session, id, spec.IsKey, false, spec.TextIn);
+ auto tableName = createTable(db, session, spec.TypeId, spec.IsKey, false, spec.TextIn);
session.Close().GetValueSync();
+
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
auto result = ExecutePgSelect(kikimr, tableName);
ValidatePgYqlResult(result, spec);
};
-
- auto testType = [&] (ui32 id, const TPgTypeTestSpec& typeSpec)
- {
- testSingleType(id, typeSpec);
-
- auto arrayId = NYql::NPg::LookupType(id).ArrayTypeId;
- auto textInArray = [&typeSpec] (auto i) {
- auto str = typeSpec.TextIn(i);
- return typeSpec.ArrayPrint(str);
+ auto testType = [&] (const TPgTypeTestSpec& spec) {
+ auto textInArray = [&spec] (auto i) {
+ auto str = spec.TextIn(i);
+ return spec.ArrayPrint(str);
};
- auto textOutArray = [&typeSpec] (auto i) {
- auto str = typeSpec.TextOut(i);
- return typeSpec.ArrayPrint(str);
+
+ auto textOutArray = [&spec] (auto i) {
+ auto str = spec.TextOut(i);
+ return spec.ArrayPrint(str);
};
- TPgTypeTestSpec arraySpec(typeSpec.IsKey, textInArray, textOutArray);
- testSingleType(arrayId, arraySpec);
+ auto arrayTypeId = NYql::NPg::LookupType(spec.TypeId).ArrayTypeId;
+ TPgTypeTestSpec arraySpec{arrayTypeId, spec.IsKey, textInArray, textOutArray};
+
+ testSingleType(spec);
+ testSingleType(arraySpec);
};
auto testByteaType = [&] () {
- TPgTypeTestSpec byteaSpec(
- true,
- [] (auto i) { return Sprintf("bytea %u", i); },
- [] (auto i) { return Sprintf("\\x627974656120%x", i + 48); }
- );
-
- TPgTypeTestSpec bytearrSpec(
- false,
- [] (auto i) { return Sprintf("{a%u, b%u}", i, i + 10); },
- [] (auto i) { return Sprintf("{\"\\\\x61%x\",\"\\\\x6231%x\"}", i + 48, i + 48); }
- );
- testSingleType(BYTEAOID, byteaSpec);
- testSingleType(BYTEAARRAYOID, bytearrSpec);
+ testSingleType(typeByteaSpec);
+ testSingleType(typeByteaArraySpec);
};
+
testByteaType();
- for (const auto& [oid, spec] : typeSpecs) {
- Cerr << oid << Endl;
- testType(oid, spec);
+
+ for (const auto& spec : typeSpecs) {
+ Cerr << spec.TypeId << Endl;
+ testType(spec);
}
}
@@ -644,88 +973,56 @@ Y_UNIT_TEST_SUITE(KqpPg) {
Y_UNIT_TEST(TableInsert) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
- auto testSingleType = [&kikimr] (ui32 id, const TPgTypeTestSpec& spec) {
+ auto testSingleType = [&kikimr] (const TPgTypeTestSpec& spec) {
auto db = kikimr.GetTableClient();
auto session = db.CreateSession().GetValueSync().GetSession();
- auto tableName = createTable(
- db,
- session,
- id,
- spec.IsKey,
- false,
- spec.TextIn,
- "",
- 0
- );
+ auto tableName = createTable(db, session, spec.TypeId, spec.IsKey, false, spec.TextIn, "", 0);
session.Close().GetValueSync();
- ExecutePgInsert(kikimr, tableName, id, spec);
+ ExecutePgInsert(kikimr, tableName, spec);
auto result = ExecutePgSelect(kikimr, tableName);
ValidatePgYqlResult(result, spec);
};
- auto testType = [&] (ui32 id, const TPgTypeTestSpec& typeSpec)
- {
- testSingleType(id, typeSpec);
- };
auto testByteaType = [&] () {
- TPgTypeTestSpec byteaSpec(
- true,
- [] (auto i) { return Sprintf("bytea %u", i); },
- [] (auto i) { return Sprintf("\\x627974656120%x", i + 48); }
- );
-
- TPgTypeTestSpec bytearrSpec(
- false,
- [] (auto i) { return Sprintf("{a%u, b%u}", i, i + 10); },
- [] (auto i) { return Sprintf("{\"\\\\x61%x\",\"\\\\x6231%x\"}", i + 48, i + 48); }
- );
- testSingleType(BYTEAOID, byteaSpec);
- testSingleType(BYTEAARRAYOID, bytearrSpec);
+ testSingleType(typeByteaSpec);
+
+ TPgTypeTestSpec typeByteaArraySpecForInsert{
+ BYTEAARRAYOID, false, typeByteaArraySpec.TextIn, typeByteaArraySpec.TextOut};
+
+ testSingleType(typeByteaArraySpecForInsert);
};
+
testByteaType();
- for (auto [oid, spec] : typeSpecs) {
- Cerr << oid << Endl;
- if (oid == CHAROID) {
+
+ for (const auto& spec : typeSpecs) {
+ Cerr << spec.TypeId << Endl;
+ if (spec.TypeId == CHAROID) {
continue;
// I cant come up with a query with explicit char conversion.
// ::char, ::character casts to pg_bpchar
}
- if (oid == MONEYOID || oid == BITOID || oid == VARBITOID) {
- spec.IsKey = false;
- // Those types do not have HashProcId, so are not hashable,
- // And we can not validate their uniqueness as keys in INSERT.
- }
- testType(oid, spec);
+ testSingleType(spec);
}
}
Y_UNIT_TEST(TableArrayInsert) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
- auto testSingleType = [&kikimr] (ui32 id, const TPgTypeTestSpec& spec) {
+ auto testSingleType = [&kikimr] (const TPgTypeTestSpec& spec) {
auto db = kikimr.GetTableClient();
auto session = db.CreateSession().GetValueSync().GetSession();
- auto arrayId = NYql::NPg::LookupType(id).ArrayTypeId;
- auto tableName = createTable(
- db,
- session,
- arrayId,
- spec.IsKey/*false*/,
- false,
- spec.TextIn,
- "",
- 0
- );
+ auto arrayId = NYql::NPg::LookupType(spec.TypeId).ArrayTypeId;
+ auto tableName = createTable(db, session, arrayId, spec.IsKey, false, spec.TextIn, "", 0);
session.Close().GetValueSync();
- ExecutePgArrayInsert(kikimr, tableName, id, spec);
+ ExecutePgArrayInsert(kikimr, tableName, spec);
auto result = ExecutePgSelect(kikimr, tableName);
TResultSetParser parser(result.GetResultSetParser(0));
for (size_t i = 0; parser.TryNextRow(); ++i) {
- auto check = [&parser, &id, &spec] (const TString& column, const TString& expected) {
+ auto check = [&parser] (const TString& column, const TString& expected) {
auto& c = parser.ColumnParser(column);
UNIT_ASSERT_VALUES_EQUAL(expected, c.GetPg().Content_);
};
@@ -734,45 +1031,37 @@ Y_UNIT_TEST_SUITE(KqpPg) {
}
};
-
- auto testType = [&] (ui32 id, const TPgTypeTestSpec& typeSpec) {
- auto textOutArray = [&typeSpec] (auto i) {
- auto str = typeSpec.TextOut(i);
- return typeSpec.ArrayPrint(str);
+ auto testType = [&] (const TPgTypeTestSpec& spec) {
+ auto textOutArray = [&spec] (auto i) {
+ auto str = spec.TextOut(i);
+ return spec.ArrayPrint(str);
};
- TPgTypeTestSpec arraySpec(false, typeSpec.TextIn, textOutArray);
- testSingleType(id, arraySpec);
+ TPgTypeTestSpec arraySpec{spec.TypeId, false, spec.TextIn, textOutArray};
+ testSingleType(arraySpec);
};
- for (auto [oid, spec] : typeSpecs) {
- Cerr << oid << Endl;
- if (oid == CHAROID) {
+ for (const auto& spec : typeSpecs) {
+ Cerr << spec.TypeId << Endl;
+ if (spec.TypeId == CHAROID) {
continue;
// I cant come up with a query with explicit char conversion.
// ::char, ::character casts to pg_bpchar
}
- if (oid == MONEYOID || oid == BITOID || oid == VARBITOID) {
- spec.IsKey = false;
- // Those types do not have HashProcId, so are not hashable,
- // And we can not validate their uniqueness as keys in INSERT.
- }
- testType(oid, spec);
+ testType(spec);
}
}
Y_UNIT_TEST(InsertFromSelect) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
- auto testSingleType = [&kikimr] (ui32 id, bool isKey,
- std::function<TString(size_t)> textIn,
- std::function<TString(size_t)> textOut)
- {
+ auto testSingleType = [&kikimr] (const TPgTypeTestSpec& spec) {
auto db = kikimr.GetTableClient();
auto session = db.CreateSession().GetValueSync().GetSession();
- auto tableName = createTable(db, session, id, isKey, false, textIn, "", 10, {"key1", "value1"});
- TString emptyTableName = "/Root/PgEmpty" + ToString(id);
- createTable(db, session, id, isKey, false, textIn, emptyTableName, 0);
+ auto tableName = createTable(db, session, spec.TypeId, spec.IsKey, false, spec.TextIn, "", 10, {"key1", "value1"});
+ TString emptyTableName = "/Root/PgEmpty" + ToString(spec.TypeId);
+ createTable(db, session, spec.TypeId, spec.IsKey, false, spec.TextIn, emptyTableName, 0);
session.Close().GetValueSync();
+
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
auto result = client.ExecuteYqlScript(
TStringBuilder() << R"(
@@ -782,22 +1071,25 @@ Y_UNIT_TEST_SUITE(KqpPg) {
UNIT_ASSERT_EQUAL(result.GetStatus(), EStatus::INTERNAL_ERROR);
};
- auto testType = [&] (ui32 id, const TPgTypeTestSpec& typeSpec)
- {
- testSingleType(id, typeSpec.IsKey, typeSpec.TextIn, typeSpec.TextOut);
- };
-
- testType(INT2OID, typeSpecs[INT2OID]);
+ for (const auto& spec : typeSpecs) {
+ Cerr << spec.TypeId << Endl;
+ if (spec.TypeId == CHAROID) {
+ continue;
+ // I cant come up with a query with explicit char conversion.
+ // ::char, ::character casts to pg_bpchar
+ }
+ testSingleType(spec);
+ }
}
Y_UNIT_TEST(CreateTable) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
- auto testSingleType = [&kikimr] (ui32 id, const TPgTypeTestSpec& spec, bool isArray)
- {
+
+ auto testSingleType = [&kikimr] (const TPgTypeTestSpec& spec, bool isArray) {
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
- auto tableName = "/Root/Pg" + ToString(id) + (isArray ? "array" : "");
- auto typeName = ((isArray) ? "_pg" : "pg") + NYql::NPg::LookupType(id).Name;
+ auto tableName = "/Root/Pg" + ToString(spec.TypeId) + (isArray ? "array" : "");
+ auto typeName = ((isArray) ? "_pg" : "pg") + NYql::NPg::LookupType(spec.TypeId).Name;
auto keyEntry = spec.IsKey ? ("key "+ typeName) : "key pgint2";
auto valueEntry = "value " + typeName;
auto req = Sprintf("\
@@ -808,17 +1100,18 @@ Y_UNIT_TEST_SUITE(KqpPg) {
);", tableName.Data(), keyEntry.Data(), valueEntry.Data());
Cerr << req << Endl;
auto result = client.ExecuteYqlScript(req).GetValueSync();
- UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
if (!isArray) {
- ExecutePgInsert(kikimr, tableName, id, spec);
+ ExecutePgInsert(kikimr, tableName, spec);
result = ExecutePgSelect(kikimr, tableName);
ValidatePgYqlResult(result, spec);
} else {
- ExecutePgArrayInsert(kikimr, tableName, id, spec);
+ ExecutePgArrayInsert(kikimr, tableName, spec);
result = ExecutePgSelect(kikimr, tableName);
TResultSetParser parser(result.GetResultSetParser(0));
for (size_t i = 0; parser.TryNextRow(); ++i) {
- auto check = [&parser, &id, &spec] (const TString& column, const TString& expected) {
+ auto check = [&parser, &spec] (const TString& column, const TString& expected) {
auto& c = parser.ColumnParser(column);
UNIT_ASSERT_VALUES_EQUAL(expected, c.GetPg().Content_);
};
@@ -828,34 +1121,26 @@ Y_UNIT_TEST_SUITE(KqpPg) {
}
};
- auto testType = [&] (ui32 id, const TPgTypeTestSpec& typeSpec)
- {
- testSingleType(id, typeSpec, false);
-
- auto textOutArray = [&typeSpec] (auto i) {
- auto str = typeSpec.TextOut(i);
- return typeSpec.ArrayPrint(str);
+ auto testType = [&] (const TPgTypeTestSpec& spec) {
+ auto textOutArray = [&spec] (auto i) {
+ auto str = spec.TextOut(i);
+ return spec.ArrayPrint(str);
};
- TPgTypeTestSpec arraySpec(false, typeSpec.TextIn, textOutArray);
- testSingleType(id, arraySpec, true);
+ TPgTypeTestSpec arraySpec{spec.TypeId, false, spec.TextIn, textOutArray};
+ testSingleType(spec, false);
+ testSingleType(arraySpec, true);
};
- for (auto [oid, spec] : typeSpecs) {
- if (oid == CHAROID) {
- continue;
- }
- if (oid == CHAROID) {
+
+ for (const auto& spec : typeSpecs) {
+ Cerr << spec.TypeId << Endl;
+ if (spec.TypeId == CHAROID) {
continue;
// I cant come up with a query with explicit char conversion.
// ::char, ::character casts to pg_bpchar
}
- if (oid == MONEYOID || oid == BITOID || oid == VARBITOID) {
- spec.IsKey = false;
- // Those types do not have HashProcId, so are not hashable,
- // And we can not validate their uniqueness as keys in INSERT.
- }
- testType(oid, spec);
+ testType(spec);
}
}
@@ -863,7 +1148,7 @@ Y_UNIT_TEST_SUITE(KqpPg) {
TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false));
TTableBuilder builder;
- UNIT_ASSERT_EXCEPTION(builder.AddNonNullableColumn("key", makePgType(INT2OID)), yexception);
+ UNIT_ASSERT_EXCEPTION(builder.AddNonNullableColumn("key", TPgType("pgint2")), yexception);
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
auto req = TStringBuilder() << R"(
diff --git a/ydb/core/persqueue/pq_impl.cpp b/ydb/core/persqueue/pq_impl.cpp
index 58d35a74199..fc14f81d847 100644
--- a/ydb/core/persqueue/pq_impl.cpp
+++ b/ydb/core/persqueue/pq_impl.cpp
@@ -634,9 +634,9 @@ void TPersQueue::ApplyNewConfigAndReply(const TActorContext& ctx)
KeySchema.clear();
KeySchema.reserve(Config.PartitionKeySchemaSize());
for (const auto& component : Config.GetPartitionKeySchema()) {
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(component.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(component.GetTypeId(),
component.HasTypeInfo() ? &component.GetTypeInfo() : nullptr);
- KeySchema.push_back(typeInfo);
+ KeySchema.push_back(typeInfoMod.TypeInfo);
}
Y_VERIFY(TopicName.size(), "Need topic name here");
@@ -759,9 +759,9 @@ void TPersQueue::ReadConfig(const NKikimrClient::TKeyValueResponse::TReadResult&
KeySchema.clear();
KeySchema.reserve(Config.PartitionKeySchemaSize());
for (const auto& component : Config.GetPartitionKeySchema()) {
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(component.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(component.GetTypeId(),
component.HasTypeInfo() ? &component.GetTypeInfo() : nullptr);
- KeySchema.push_back(typeInfo);
+ KeySchema.push_back(typeInfoMod.TypeInfo);
}
ui32 cacheSize = CACHE_SIZE;
diff --git a/ydb/core/protos/type_info.proto b/ydb/core/protos/type_info.proto
index 669e0f5ee7b..3ce4b6ed831 100644
--- a/ydb/core/protos/type_info.proto
+++ b/ydb/core/protos/type_info.proto
@@ -3,4 +3,5 @@ option java_package = "ru.yandex.kikimr.proto";
message TTypeInfo {
optional uint32 PgTypeId = 1;
+ optional string PgTypeMod = 2;
}
diff --git a/ydb/core/scheme/scheme_type_info.cpp b/ydb/core/scheme/scheme_type_info.cpp
index f655cd5f192..5631b6de550 100644
--- a/ydb/core/scheme/scheme_type_info.cpp
+++ b/ydb/core/scheme/scheme_type_info.cpp
@@ -5,9 +5,9 @@
namespace NKikimr::NScheme {
-const char* TypeName(const TTypeInfo typeInfo) {
+::TString TypeName(const TTypeInfo typeInfo, const ::TString& typeMod) {
if (typeInfo.GetTypeId() == NScheme::NTypeIds::Pg) {
- return NPg::PgTypeNameFromTypeDesc(typeInfo.GetTypeDesc());
+ return NPg::PgTypeNameFromTypeDesc(typeInfo.GetTypeDesc(), typeMod);
} else {
return TypeName(typeInfo.GetTypeId());
}
diff --git a/ydb/core/scheme/scheme_type_info.h b/ydb/core/scheme/scheme_type_info.h
index f36f98112a6..307486ffdb8 100644
--- a/ydb/core/scheme/scheme_type_info.h
+++ b/ydb/core/scheme/scheme_type_info.h
@@ -4,6 +4,6 @@
namespace NKikimr::NScheme {
-const char* TypeName(const TTypeInfo typeInfo);
+::TString TypeName(const TTypeInfo typeInfo, const ::TString& typeMod = {});
} // NKikimr::NScheme
diff --git a/ydb/core/scheme/scheme_types_proto.cpp b/ydb/core/scheme/scheme_types_proto.cpp
index 02bfbda2551..97faf06ddf1 100644
--- a/ydb/core/scheme/scheme_types_proto.cpp
+++ b/ydb/core/scheme/scheme_types_proto.cpp
@@ -3,24 +3,32 @@
namespace NKikimr::NScheme {
-TProtoColumnType ProtoColumnTypeFromTypeInfo(const TTypeInfo typeInfo) {
+TProtoColumnType ProtoColumnTypeFromTypeInfoMod(const TTypeInfo typeInfo, const ::TString& typeMod) {
TProtoColumnType columnType;
columnType.TypeId = (ui32)typeInfo.GetTypeId();
if (typeInfo.GetTypeId() == NTypeIds::Pg) {
Y_VERIFY(typeInfo.GetTypeDesc(), "no pg type descriptor");
columnType.TypeInfo = NKikimrProto::TTypeInfo();
columnType.TypeInfo->SetPgTypeId(NPg::PgTypeIdFromTypeDesc(typeInfo.GetTypeDesc()));
+ if (typeMod) {
+ columnType.TypeInfo->SetPgTypeMod(typeMod);
+ }
}
return columnType;
}
-TTypeInfo TypeInfoFromProtoColumnType(ui32 typeId, const NKikimrProto::TTypeInfo* typeInfo) {
+TTypeInfoMod TypeInfoModFromProtoColumnType(ui32 typeId, const NKikimrProto::TTypeInfo* typeInfo) {
auto type = (TTypeId)typeId;
if (type == NTypeIds::Pg) {
- Y_VERIFY(typeInfo);
- return TTypeInfo(type, NPg::TypeDescFromPgTypeId(typeInfo->GetPgTypeId()));
+ Y_VERIFY(typeInfo, "no type info for pg type");
+ TTypeInfoMod res;
+ res.TypeInfo = TTypeInfo(type, NPg::TypeDescFromPgTypeId(typeInfo->GetPgTypeId()));
+ if (typeInfo->HasPgTypeMod()) {
+ res.TypeMod = typeInfo->GetPgTypeMod();
+ }
+ return res;
}
- return TTypeInfo(type);
+ return {TTypeInfo(type), ""};
}
} // namespace NKikimr::NScheme
diff --git a/ydb/core/scheme/scheme_types_proto.h b/ydb/core/scheme/scheme_types_proto.h
index 43c8789579c..ce46ccad116 100644
--- a/ydb/core/scheme/scheme_types_proto.h
+++ b/ydb/core/scheme/scheme_types_proto.h
@@ -10,8 +10,13 @@ struct TProtoColumnType {
std::optional<NKikimrProto::TTypeInfo> TypeInfo;
};
-TProtoColumnType ProtoColumnTypeFromTypeInfo(const TTypeInfo typeInfo);
+TProtoColumnType ProtoColumnTypeFromTypeInfoMod(const TTypeInfo typeInfo, const ::TString& typeMod);
-TTypeInfo TypeInfoFromProtoColumnType(ui32 typeId, const NKikimrProto::TTypeInfo* typeInfo);
+struct TTypeInfoMod {
+ TTypeInfo TypeInfo;
+ ::TString TypeMod;
+};
+
+TTypeInfoMod TypeInfoModFromProtoColumnType(ui32 typeId, const NKikimrProto::TTypeInfo* typeInfo);
} // namespace NKikimr::NScheme
diff --git a/ydb/core/sys_view/common/schema.cpp b/ydb/core/sys_view/common/schema.cpp
index 78d7c1bf81a..80ef81d4dec 100644
--- a/ydb/core/sys_view/common/schema.cpp
+++ b/ydb/core/sys_view/common/schema.cpp
@@ -114,7 +114,7 @@ private:
static void Fill(TSchema& schema) {
schema.Columns[Column::ColumnId] = TSysTables::TTableColumnInfo(
Table::template TableColumns<Column>::GetColumnName(),
- Column::ColumnId, NScheme::TTypeInfo(Column::ColumnType), -1);
+ Column::ColumnId, NScheme::TTypeInfo(Column::ColumnType), "", -1);
}
};
diff --git a/ydb/core/tablet_flat/flat_cxx_database.h b/ydb/core/tablet_flat/flat_cxx_database.h
index 021a520859b..f15905864b0 100644
--- a/ydb/core/tablet_flat/flat_cxx_database.h
+++ b/ydb/core/tablet_flat/flat_cxx_database.h
@@ -2197,7 +2197,7 @@ struct TStaticSchemaFiller {
schema.Columns[Column::ColumnId] = NTable::TColumn(
TTable::template TableColumns<Column>::GetColumnName(),
Column::ColumnId,
- NScheme::TTypeInfo(Column::ColumnType));
+ NScheme::TTypeInfo(Column::ColumnType), "");
}
};
diff --git a/ydb/core/tablet_flat/flat_dbase_apply.cpp b/ydb/core/tablet_flat/flat_dbase_apply.cpp
index 32ec4f02df6..dc23becc890 100644
--- a/ydb/core/tablet_flat/flat_dbase_apply.cpp
+++ b/ydb/core/tablet_flat/flat_dbase_apply.cpp
@@ -1,6 +1,7 @@
#include "flat_dbase_apply.h"
#include <ydb/core/base/localdb.h>
+#include <ydb/core/scheme/scheme_types_proto.h>
namespace NKikimr {
namespace NTable {
@@ -32,9 +33,11 @@ bool TSchemeModifier::Apply(const TAlterRecord &delta)
null = TCell(raw.data(), raw.size());
}
- ui32 pgTypeId = delta.HasColumnTypeInfo() ? delta.GetColumnTypeInfo().GetPgTypeId() : 0;
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(delta.GetColumnType(),
+ delta.HasColumnTypeInfo() ? &delta.GetColumnTypeInfo() : nullptr);
+ ui32 pgTypeId = NPg::PgTypeIdFromTypeDesc(typeInfoMod.TypeInfo.GetTypeDesc());
changes = AddPgColumn(table, delta.GetColumnName(), delta.GetColumnId(),
- delta.GetColumnType(), pgTypeId, delta.GetNotNull(), null);
+ delta.GetColumnType(), pgTypeId, typeInfoMod.TypeMod, delta.GetNotNull(), null);
} else if (action == TAlterRecord::DropColumn) {
changes = DropColumn(table, delta.GetColumnId());
} else if (action == TAlterRecord::AddColumnToKey) {
@@ -224,10 +227,10 @@ bool TSchemeModifier::DropTable(ui32 id)
bool TSchemeModifier::AddColumn(ui32 tid, const TString &name, ui32 id, ui32 type, bool notNull, TCell null)
{
Y_VERIFY(type != (ui32)NScheme::NTypeIds::Pg, "No pg type data");
- return AddPgColumn(tid, name, id, type, 0, notNull, null);
+ return AddPgColumn(tid, name, id, type, 0, "", notNull, null);
}
-bool TSchemeModifier::AddPgColumn(ui32 tid, const TString &name, ui32 id, ui32 type, ui32 pgType, bool notNull, TCell null)
+bool TSchemeModifier::AddPgColumn(ui32 tid, const TString &name, ui32 id, ui32 type, ui32 pgType, const TString& pgTypeMod, bool notNull, TCell null)
{
auto *table = Table(tid);
@@ -259,9 +262,10 @@ bool TSchemeModifier::AddPgColumn(ui32 tid, const TString &name, ui32 id, ui32 t
Y_VERIFY_S(itName->second == id, describeFailure());
// Sanity check that this column exists and types match
Y_VERIFY(it != table->Columns.end() && it->second.Name == name);
- Y_VERIFY_S(it->second.PType == typeInfo,
+ Y_VERIFY_S(it->second.PType == typeInfo && it->second.PTypeMod == pgTypeMod,
"Table " << tid << " '" << table->Name << "' column " << id << " '" << name
- << "' expected type " << NScheme::TypeName(typeInfo) << ", existing type " << NScheme::TypeName(it->second.PType));
+ << "' expected type " << NScheme::TypeName(typeInfo, pgTypeMod)
+ << ", existing type " << NScheme::TypeName(it->second.PType, it->second.PTypeMod));
return false;
}
@@ -269,16 +273,17 @@ bool TSchemeModifier::AddPgColumn(ui32 tid, const TString &name, ui32 id, ui32 t
// We assume column is renamed when the same id already exists
if (it != table->Columns.end()) {
- Y_VERIFY_S(it->second.PType == typeInfo,
+ Y_VERIFY_S(it->second.PType == typeInfo && it->second.PTypeMod == pgTypeMod,
"Table " << tid << " '" << table->Name << "' column " << id << " '" << it->second.Name << "' renamed to '" << name << "'"
- << " with type " << NScheme::TypeName(typeInfo) << ", existing type " << NScheme::TypeName(it->second.PType));
+ << " with type " << NScheme::TypeName(typeInfo, pgTypeMod)
+ << ", existing type " << NScheme::TypeName(it->second.PType, it->second.PTypeMod));
table->ColumnNames.erase(it->second.Name);
it->second.Name = name;
table->ColumnNames.emplace(name, id);
return true;
}
- auto pr = table->Columns.emplace(id, TColumn(name, id, typeInfo, notNull));
+ auto pr = table->Columns.emplace(id, TColumn(name, id, typeInfo, pgTypeMod, notNull));
Y_VERIFY(pr.second);
it = pr.first;
table->ColumnNames.emplace(name, id);
diff --git a/ydb/core/tablet_flat/flat_dbase_apply.h b/ydb/core/tablet_flat/flat_dbase_apply.h
index b9008b73abb..c90113c804c 100644
--- a/ydb/core/tablet_flat/flat_dbase_apply.h
+++ b/ydb/core/tablet_flat/flat_dbase_apply.h
@@ -33,7 +33,7 @@ namespace NTable {
bool AddTable(const TString& name, ui32 id);
bool DropTable(ui32 id);
bool AddColumn(ui32 table, const TString& name, ui32 id, ui32 type, bool notNull, TCell null = { });
- bool AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type, ui32 pgType, bool notNull, TCell null = { });
+ bool AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type, ui32 pgType, const TString& pgTypeMod, bool notNull, TCell null = { });
bool DropColumn(ui32 table, ui32 id);
bool AddColumnToFamily(ui32 table, ui32 column, ui32 family);
bool AddColumnToKey(ui32 table, ui32 column);
diff --git a/ydb/core/tablet_flat/flat_dbase_scheme.cpp b/ydb/core/tablet_flat/flat_dbase_scheme.cpp
index 2c973fa9044..0292e12d4cf 100644
--- a/ydb/core/tablet_flat/flat_dbase_scheme.cpp
+++ b/ydb/core/tablet_flat/flat_dbase_scheme.cpp
@@ -29,7 +29,8 @@ TAutoPtr<TSchemeChanges> TScheme::GetSnapshot() const {
const auto &col = it.second;
delta.AddPgColumn(table, col.Name, it.first, col.PType.GetTypeId(),
- NPg::PgTypeIdFromTypeDesc(col.PType.GetTypeDesc()), col.NotNull, col.Null);
+ NPg::PgTypeIdFromTypeDesc(col.PType.GetTypeDesc()),
+ col.PTypeMod, col.NotNull, col.Null);
delta.AddColumnToFamily(table, it.first, col.Family);
}
@@ -99,10 +100,10 @@ TAlter& TAlter::DropTable(ui32 id)
TAlter& TAlter::AddColumn(ui32 table, const TString& name, ui32 id, ui32 type, bool notNull, TCell null)
{
Y_VERIFY(type != (ui32)NScheme::NTypeIds::Pg, "No pg type data");
- return AddPgColumn(table, name, id, type, 0, notNull, null);
+ return AddPgColumn(table, name, id, type, 0, "", notNull, null);
}
-TAlter& TAlter::AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type, ui32 pgType, bool notNull, TCell null)
+TAlter& TAlter::AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type, ui32 pgType, const TString& pgTypeMod, bool notNull, TCell null)
{
TAlterRecord& delta = *Log.AddDelta();
delta.SetDeltaType(TAlterRecord::AddColumn);
@@ -112,6 +113,9 @@ TAlter& TAlter::AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type,
delta.SetColumnType(type);
if (pgType != 0) {
delta.MutableColumnTypeInfo()->SetPgTypeId(pgType);
+ if (!pgTypeMod.empty()) {
+ delta.MutableColumnTypeInfo()->SetPgTypeMod(pgTypeMod);
+ }
}
delta.SetNotNull(notNull);
diff --git a/ydb/core/tablet_flat/flat_dbase_scheme.h b/ydb/core/tablet_flat/flat_dbase_scheme.h
index 56cc65ec94d..85098da115e 100644
--- a/ydb/core/tablet_flat/flat_dbase_scheme.h
+++ b/ydb/core/tablet_flat/flat_dbase_scheme.h
@@ -247,7 +247,7 @@ public:
TAlter& AddTable(const TString& name, ui32 id);
TAlter& DropTable(ui32 id);
TAlter& AddColumn(ui32 table, const TString& name, ui32 id, ui32 type, bool notNull, TCell null = { });
- TAlter& AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type, ui32 pgType, bool notNull, TCell null = { });
+ TAlter& AddPgColumn(ui32 table, const TString& name, ui32 id, ui32 type, ui32 pgType, const TString& pgTypeMod, bool notNull, TCell null = { });
TAlter& DropColumn(ui32 table, ui32 id);
TAlter& AddColumnToFamily(ui32 table, ui32 column, ui32 family);
TAlter& AddFamily(ui32 table, ui32 family, ui32 room);
diff --git a/ydb/core/tablet_flat/flat_executor.cpp b/ydb/core/tablet_flat/flat_executor.cpp
index 1aded82071f..b02ada11bf7 100644
--- a/ydb/core/tablet_flat/flat_executor.cpp
+++ b/ydb/core/tablet_flat/flat_executor.cpp
@@ -3883,7 +3883,6 @@ void TExecutor::RenderHtmlCounters(NMon::TEvRemoteHttpInfo::TPtr &ev) const {
void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const {
auto cgi = ev->Get()->Cgi();
TStringStream str;
- const NScheme::TTypeRegistry& tr = *AppData()->TypeRegistry;
if (cgi.Has("force_compaction")) {
bool ok;
@@ -3971,7 +3970,7 @@ void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const {
TABLER() {
TABLED() {str << col.Name;}
TABLED() {str << col.Id;}
- TABLED() {str << tr.GetTypeName(col.PType.GetTypeId());}
+ TABLED() {str << NScheme::TypeName(col.PType, col.PTypeMod);}
TABLED() {str << (isKey ? ToString(col.KeyOrder) : "");}
}
}
diff --git a/ydb/core/tablet_flat/flat_table_column.h b/ydb/core/tablet_flat/flat_table_column.h
index 49f8fb7a9d0..ac2a4095d4b 100644
--- a/ydb/core/tablet_flat/flat_table_column.h
+++ b/ydb/core/tablet_flat/flat_table_column.h
@@ -15,9 +15,11 @@ namespace NTable {
TColumn() = default;
- TColumn(const TString& name, TTag tag, NScheme::TTypeInfo type, bool notNull = false)
+ TColumn(const TString& name, TTag tag, NScheme::TTypeInfo type,
+ const TString& typeMod, bool notNull = false)
: Id(tag)
, PType(type)
+ , PTypeMod(typeMod)
, Name(name)
, NotNull(notNull)
{
@@ -29,6 +31,7 @@ namespace NTable {
return
Id == col.Id
&& PType == col.PType
+ && PTypeMod == col.PTypeMod
&& KeyOrder == col.KeyOrder
&& Name == col.Name
&& Family == col.Family
@@ -48,6 +51,7 @@ namespace NTable {
NTable::TTag Id = Max<TTag>();
NScheme::TTypeInfo PType;
+ TString PTypeMod;
TString Name;
ui32 Family = LeaderFamily;
NTable::TPos KeyOrder = Max<TPos>();
diff --git a/ydb/core/tablet_flat/flat_table_part.cpp b/ydb/core/tablet_flat/flat_table_part.cpp
index ff042b266ff..405b231f68b 100644
--- a/ydb/core/tablet_flat/flat_table_part.cpp
+++ b/ydb/core/tablet_flat/flat_table_part.cpp
@@ -53,8 +53,8 @@ TIntrusiveConstPtr<TPartScheme> TPartScheme::Parse(TArrayRef<const char> raw, bo
cols.emplace_back();
cols.back().Tag = one.GetTag();
- cols.back().TypeInfo = NScheme::TypeInfoFromProtoColumnType(one.GetType(),
- one.HasTypeInfo() ? &one.GetTypeInfo() : nullptr);
+ cols.back().TypeInfo = NScheme::TypeInfoModFromProtoColumnType(one.GetType(),
+ one.HasTypeInfo() ? &one.GetTypeInfo() : nullptr).TypeInfo;
cols.back().Pos = cols.size() - 1;
cols.back().Group = one.GetGroup();
@@ -193,7 +193,7 @@ TSharedData TPartScheme::Serialize() const
for (const auto& col : AllColumns) {
auto* pb = proto.AddColumns();
pb->SetTag(col.Tag);
- auto protoType = NScheme::ProtoColumnTypeFromTypeInfo(col.TypeInfo);
+ auto protoType = NScheme::ProtoColumnTypeFromTypeInfoMod(col.TypeInfo, "");
pb->SetType(protoType.TypeId);
if (protoType.TypeInfo) {
*pb->MutableTypeInfo() = *protoType.TypeInfo;
diff --git a/ydb/core/tablet_flat/test/libs/rows/layout.h b/ydb/core/tablet_flat/test/libs/rows/layout.h
index 6657b4fd08a..4e854a64896 100644
--- a/ydb/core/tablet_flat/test/libs/rows/layout.h
+++ b/ydb/core/tablet_flat/test/libs/rows/layout.h
@@ -23,7 +23,7 @@ namespace NTest{
Tags_.push_back(tag);
// pg types are not supported
- Cols.emplace_back("", tag, NScheme::TTypeInfo(type));
+ Cols.emplace_back("", tag, NScheme::TTypeInfo(type), "");
Cols.back().Family = group;
Cols.back().SetDefault(null);
diff --git a/ydb/core/tablet_flat/ut_pg/flat_database_pg_ut.cpp b/ydb/core/tablet_flat/ut_pg/flat_database_pg_ut.cpp
index 4abd5e70191..5130aaeb4da 100644
--- a/ydb/core/tablet_flat/ut_pg/flat_database_pg_ut.cpp
+++ b/ydb/core/tablet_flat/ut_pg/flat_database_pg_ut.cpp
@@ -36,16 +36,16 @@ Y_UNIT_TEST_SUITE(TFlatDatabasePgTest) {
db.Begin();
db->Alter()
.AddTable("TestTable", tableId)
- .AddPgColumn(tableId, "boolean", IdBool, NScheme::NTypeIds::Pg, BOOLOID, false)
- .AddPgColumn(tableId, "char", IdChar, NScheme::NTypeIds::Pg, CHAROID, false)
- .AddPgColumn(tableId, "int2", IdInt2, NScheme::NTypeIds::Pg, INT2OID, false)
- .AddPgColumn(tableId, "int4", IdInt4, NScheme::NTypeIds::Pg, INT4OID, false)
- .AddPgColumn(tableId, "int8", IdInt8, NScheme::NTypeIds::Pg, INT8OID, false)
- .AddPgColumn(tableId, "float4", IdFloat4, NScheme::NTypeIds::Pg, FLOAT4OID, false)
- .AddPgColumn(tableId, "float8", IdFloat8, NScheme::NTypeIds::Pg, FLOAT8OID, false)
- .AddPgColumn(tableId, "text", IdText, NScheme::NTypeIds::Pg, TEXTOID, false)
- .AddPgColumn(tableId, "bytea", IdBytea, NScheme::NTypeIds::Pg, BYTEAOID, false)
- .AddPgColumn(tableId, "bpchar", IdBpchar, NScheme::NTypeIds::Pg, BPCHAROID, false)
+ .AddPgColumn(tableId, "boolean", IdBool, NScheme::NTypeIds::Pg, BOOLOID, "", false)
+ .AddPgColumn(tableId, "char", IdChar, NScheme::NTypeIds::Pg, CHAROID, "", false)
+ .AddPgColumn(tableId, "int2", IdInt2, NScheme::NTypeIds::Pg, INT2OID, "", false)
+ .AddPgColumn(tableId, "int4", IdInt4, NScheme::NTypeIds::Pg, INT4OID, "", false)
+ .AddPgColumn(tableId, "int8", IdInt8, NScheme::NTypeIds::Pg, INT8OID, "", false)
+ .AddPgColumn(tableId, "float4", IdFloat4, NScheme::NTypeIds::Pg, FLOAT4OID, "", false)
+ .AddPgColumn(tableId, "float8", IdFloat8, NScheme::NTypeIds::Pg, FLOAT8OID, "", false)
+ .AddPgColumn(tableId, "text", IdText, NScheme::NTypeIds::Pg, TEXTOID, "", false)
+ .AddPgColumn(tableId, "bytea", IdBytea, NScheme::NTypeIds::Pg, BYTEAOID, "", false)
+ .AddPgColumn(tableId, "bpchar", IdBpchar, NScheme::NTypeIds::Pg, BPCHAROID, "", false)
.AddColumnToKey(tableId, IdText)
.AddColumnToKey(tableId, IdBytea)
.AddColumnToKey(tableId, IdInt2)
diff --git a/ydb/core/tx/columnshard/columnshard_impl.cpp b/ydb/core/tx/columnshard/columnshard_impl.cpp
index 7cb866d4e73..d45c08eec84 100644
--- a/ydb/core/tx/columnshard/columnshard_impl.cpp
+++ b/ydb/core/tx/columnshard/columnshard_impl.cpp
@@ -989,9 +989,9 @@ NOlap::TIndexInfo TColumnShard::ConvertSchema(const NKikimrSchemeOp::TColumnTabl
for (const auto& col : schema.GetColumns()) {
const ui32 id = col.GetId();
const TString& name = col.GetName();
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
- indexInfo.Columns[id] = NTable::TColumn(name, id, typeInfo);
+ indexInfo.Columns[id] = NTable::TColumn(name, id, typeInfoMod.TypeInfo, typeInfoMod.TypeMod);
indexInfo.ColumnNames[name] = id;
}
diff --git a/ydb/core/tx/columnshard/columnshard_ut_common.cpp b/ydb/core/tx/columnshard/columnshard_ut_common.cpp
index 872d4df5bd1..f9572611454 100644
--- a/ydb/core/tx/columnshard/columnshard_ut_common.cpp
+++ b/ydb/core/tx/columnshard/columnshard_ut_common.cpp
@@ -130,7 +130,7 @@ void ScanIndexStats(TTestBasicRuntime& runtime, TActorId& sender, const TVector<
auto ydbSchema = PrimaryIndexStatsSchema;
for (const auto& col : ydbSchema.Columns) {
record.AddColumnTags(col.second.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(col.second.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(col.second.PType, col.second.PTypeMod);
record.AddColumnTypes(columnType.TypeId);
if (columnType.TypeInfo) {
*record.AddColumnTypeInfos() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/columnshard/columnshard_ut_common.h b/ydb/core/tx/columnshard/columnshard_ut_common.h
index afb459a5de3..c557a367684 100644
--- a/ydb/core/tx/columnshard/columnshard_ut_common.h
+++ b/ydb/core/tx/columnshard/columnshard_ut_common.h
@@ -173,7 +173,7 @@ struct TTestSchema {
NKikimrSchemeOp::TOlapColumnDescription col;
col.SetId(id);
col.SetName(name);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(type, "");
col.SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*col.MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/columnshard/engines/ut_logs_engine.cpp b/ydb/core/tx/columnshard/engines/ut_logs_engine.cpp
index 423318b75fe..02252c098b1 100644
--- a/ydb/core/tx/columnshard/engines/ut_logs_engine.cpp
+++ b/ydb/core/tx/columnshard/engines/ut_logs_engine.cpp
@@ -180,7 +180,7 @@ TIndexInfo TestTableInfo(const TVector<std::pair<TString, TTypeInfo>>& ydbSchema
auto& name = ydbSchema[i].first;
auto& type = ydbSchema[i].second;
- indexInfo.Columns[id] = NTable::TColumn(name, id, type);
+ indexInfo.Columns[id] = NTable::TColumn(name, id, type, "");
indexInfo.ColumnNames[name] = id;
}
diff --git a/ydb/core/tx/datashard/build_index.cpp b/ydb/core/tx/datashard/build_index.cpp
index 1eb08345a05..2be7f1cb11a 100644
--- a/ydb/core/tx/datashard/build_index.cpp
+++ b/ydb/core/tx/datashard/build_index.cpp
@@ -64,7 +64,10 @@ static TTags BuildTags(const TColumnsTags& allTags, const TVector<TString>& inde
static void ProtoYdbTypeFromTypeInfo(Ydb::Type* type, const NScheme::TTypeInfo typeInfo) {
if (typeInfo.GetTypeId() == NScheme::NTypeIds::Pg) {
- type->mutable_pg_type()->set_oid(NPg::PgTypeIdFromTypeDesc(typeInfo.GetTypeDesc()));
+ auto* typeDesc = typeInfo.GetTypeDesc();
+ auto* pg = type->mutable_pg_type();
+ pg->set_type_name(NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_oid(NPg::PgTypeIdFromTypeDesc(typeDesc));
} else {
type->set_type_id((Ydb::Type::PrimitiveTypeId)typeInfo.GetTypeId());
}
diff --git a/ydb/core/tx/datashard/datashard_kqp.cpp b/ydb/core/tx/datashard/datashard_kqp.cpp
index 6839de09103..a41e12da5e6 100644
--- a/ydb/core/tx/datashard/datashard_kqp.cpp
+++ b/ydb/core/tx/datashard/datashard_kqp.cpp
@@ -314,9 +314,10 @@ using TWriteOpMeta = NKikimrTxDataShard::TKqpTransaction::TDataTaskMeta::TWriteO
using TColumnMeta = NKikimrTxDataShard::TKqpTransaction::TColumnMeta;
NTable::TColumn GetColumn(const TColumnMeta& columnMeta) {
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(columnMeta.GetType(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(columnMeta.GetType(),
columnMeta.HasTypeInfo() ? &columnMeta.GetTypeInfo() : nullptr);
- return NTable::TColumn(columnMeta.GetName(), columnMeta.GetId(), typeInfo);
+ return NTable::TColumn(columnMeta.GetName(), columnMeta.GetId(),
+ typeInfoMod.TypeInfo, typeInfoMod.TypeMod);
}
TVector<NTable::TColumn> GetColumns(const TReadOpMeta& readMeta) {
diff --git a/ydb/core/tx/datashard/datashard_user_table.cpp b/ydb/core/tx/datashard/datashard_user_table.cpp
index 8a8016c475b..2a3558d909e 100644
--- a/ydb/core/tx/datashard/datashard_user_table.cpp
+++ b/ydb/core/tx/datashard/datashard_user_table.cpp
@@ -219,9 +219,9 @@ void TUserTable::ParseProto(const NKikimrSchemeOp::TTableDescription& descr)
for (const auto& col : descr.GetColumns()) {
TUserColumn& column = Columns[col.GetId()];
if (column.Name.empty()) {
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
- column = TUserColumn(typeInfo, col.GetName());
+ column = TUserColumn(typeInfoMod.TypeInfo, typeInfoMod.TypeMod, col.GetName());
}
column.Family = col.GetFamily();
column.NotNull = col.GetNotNull();
@@ -334,7 +334,7 @@ void TUserTable::AlterSchema() {
auto descr = schema.AddColumns();
descr->SetName(column.Name);
descr->SetId(col.first);
- auto protoType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto protoType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
descr->SetTypeId(protoType.TypeId);
if (protoType.TypeInfo) {
*descr->MutableTypeInfo() = *protoType.TypeInfo;
@@ -397,9 +397,9 @@ void TUserTable::DoApplyCreate(
ui32 columnId = col.first;
const TUserColumn& column = col.second;
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
ui32 pgTypeId = columnType.TypeInfo ? columnType.TypeInfo->GetPgTypeId() : 0;
- alter.AddPgColumn(tid, column.Name, columnId, columnType.TypeId, pgTypeId, column.NotNull);
+ alter.AddPgColumn(tid, column.Name, columnId, columnType.TypeId, pgTypeId, column.TypeMod, column.NotNull);
alter.AddColumnToFamily(tid, columnId, column.Family);
}
@@ -501,9 +501,9 @@ void TUserTable::ApplyAlter(
if (!oldTable.Columns.contains(colId)) {
for (ui32 tid : tids) {
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.Type);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod);
ui32 pgTypeId = columnType.TypeInfo ? columnType.TypeInfo->GetPgTypeId() : 0;
- alter.AddPgColumn(tid, column.Name, colId, columnType.TypeId, pgTypeId, column.NotNull);
+ alter.AddPgColumn(tid, column.Name, colId, columnType.TypeId, pgTypeId, column.TypeMod, column.NotNull);
}
}
diff --git a/ydb/core/tx/datashard/datashard_user_table.h b/ydb/core/tx/datashard/datashard_user_table.h
index 409e6773886..42e7dd5ae1d 100644
--- a/ydb/core/tx/datashard/datashard_user_table.h
+++ b/ydb/core/tx/datashard/datashard_user_table.h
@@ -233,13 +233,15 @@ struct TUserTable : public TThrRefBase {
struct TUserColumn {
NScheme::TTypeInfo Type;
+ TString TypeMod;
TString Name;
bool IsKey;
ui32 Family = 0;
bool NotNull = false;
- TUserColumn(NScheme::TTypeInfo type, TString name, bool isKey = false)
+ TUserColumn(NScheme::TTypeInfo type, TString typeMod, TString name, bool isKey = false)
: Type(type)
+ , TypeMod(typeMod)
, Name(name)
, IsKey(isKey)
{}
diff --git a/ydb/core/tx/datashard/datashard_ut_common.cpp b/ydb/core/tx/datashard/datashard_ut_common.cpp
index 5ade7fe5bf3..9b921ca7739 100644
--- a/ydb/core/tx/datashard/datashard_ut_common.cpp
+++ b/ydb/core/tx/datashard/datashard_ut_common.cpp
@@ -199,9 +199,9 @@ void TTester::RegisterTableInResolver(const TString& schemeText)
keyIdx = ki;
}
}
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(c.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(c.GetTypeId(),
c.HasTypeInfo() ? &c.GetTypeInfo() : nullptr);
- table.Columns.insert(std::make_pair(c.GetName(), TColumn{c.GetId(), keyIdx, typeInfo, 0, EColumnTypeConstraint::Nullable}));
+ table.Columns.insert(std::make_pair(c.GetName(), TColumn{c.GetId(), keyIdx, typeInfoMod.TypeInfo, 0, EColumnTypeConstraint::Nullable}));
}
DbSchemeResolver.AddTable(table);
}
diff --git a/ydb/core/tx/datashard/import_common.h b/ydb/core/tx/datashard/import_common.h
index 7ae51dfbfb2..241246a85e9 100644
--- a/ydb/core/tx/datashard/import_common.h
+++ b/ydb/core/tx/datashard/import_common.h
@@ -81,10 +81,11 @@ public:
return ColumnNameIndex.contains(name);
}
- NScheme::TTypeInfo GetColumnType(const TString& name) const {
+ std::pair<NScheme::TTypeInfo, TString> GetColumnType(const TString& name) const {
auto it = ColumnNameIndex.find(name);
Y_VERIFY(it != ColumnNameIndex.end());
- return it->second->second.Type;
+ auto& column = it->second->second;
+ return {column.Type, column.TypeMod};
}
const TVector<ui32>& GetKeyColumnIds() const {
diff --git a/ydb/core/tx/datashard/import_s3.cpp b/ydb/core/tx/datashard/import_s3.cpp
index cb91713f93a..14778c2cae4 100644
--- a/ydb/core/tx/datashard/import_s3.cpp
+++ b/ydb/core/tx/datashard/import_s3.cpp
@@ -527,9 +527,9 @@ class TS3Downloader: public TActorBootstrapped<TS3Downloader> {
columnOrderTypes.reserve(Scheme.GetColumns().size());
for (const auto& column : Scheme.GetColumns()) {
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(column.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(column.GetTypeId(),
column.HasTypeInfo() ? &column.GetTypeInfo() : nullptr);
- columnOrderTypes.emplace_back(TableInfo.KeyOrder(column.GetName()), typeInfo);
+ columnOrderTypes.emplace_back(TableInfo.KeyOrder(column.GetName()), typeInfoMod.TypeInfo);
}
TVector<TCell> keys;
@@ -627,14 +627,14 @@ class TS3Downloader: public TActorBootstrapped<TS3Downloader> {
<< ": name# " << column.GetName());
}
- const auto typeInfo = TableInfo.GetColumnType(column.GetName());
- auto columnTypeInfo = NScheme::TypeInfoFromProtoColumnType(column.GetTypeId(),
+ const auto type = TableInfo.GetColumnType(column.GetName());
+ auto schemeType = NScheme::TypeInfoModFromProtoColumnType(column.GetTypeId(),
column.HasTypeInfo() ? &column.GetTypeInfo() : nullptr);
- if (typeInfo != columnTypeInfo) {
+ if (type.first != schemeType.TypeInfo || type.second != schemeType.TypeMod) {
return finish(TStringBuilder() << "Scheme mismatch: column type mismatch"
<< ": name# " << column.GetName()
- << ", expected# " << NScheme::TypeName(typeInfo)
- << ", got# " << NScheme::TypeName(columnTypeInfo));
+ << ", expected# " << NScheme::TypeName(type.first, type.second)
+ << ", got# " << NScheme::TypeName(schemeType.TypeInfo, schemeType.TypeMod));
}
}
diff --git a/ydb/core/tx/datashard/read_table_scan.cpp b/ydb/core/tx/datashard/read_table_scan.cpp
index efd5640606a..9b12fe7ac74 100644
--- a/ydb/core/tx/datashard/read_table_scan.cpp
+++ b/ydb/core/tx/datashard/read_table_scan.cpp
@@ -123,9 +123,9 @@ public:
, ResultStream(ResultString)
{
for (auto &col : request.GetColumns()) {
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
- ColTypes.push_back(typeInfo);
+ ColTypes.push_back(typeInfoMod.TypeInfo);
}
}
@@ -257,12 +257,17 @@ private:
auto *meta = res.add_columns();
meta->set_name(col.GetName());
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
if (col.GetTypeId() == NScheme::NTypeIds::Pg) {
- auto pgType = meta->mutable_type()->mutable_pg_type();
- pgType->set_oid(NPg::PgTypeIdFromTypeDesc(typeInfo.GetTypeDesc()));
+ auto* pg = meta->mutable_type()->mutable_pg_type();
+ auto* typeDesc = typeInfoMod.TypeInfo.GetTypeDesc();
+ pg->set_type_name(NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_type_modifier(typeInfoMod.TypeMod);
+ pg->set_oid(NPg::PgTypeIdFromTypeDesc(typeDesc));
+ pg->set_typlen(0);
+ pg->set_typmod(0);
} else {
auto id = static_cast<NYql::NProto::TypeIds>(col.GetTypeId());
if (id == NYql::NProto::Decimal) {
diff --git a/ydb/core/tx/datashard/sys_tables.h b/ydb/core/tx/datashard/sys_tables.h
index ff02286561b..51abbc525d7 100644
--- a/ydb/core/tx/datashard/sys_tables.h
+++ b/ydb/core/tx/datashard/sys_tables.h
@@ -11,14 +11,16 @@ struct TSysTables {
TString Name;
ui32 Id = 0;
NScheme::TTypeInfo PType;
+ TString PTypeMod;
i32 KeyOrder = -1;
TTableColumnInfo() = default;
- TTableColumnInfo(TString name, ui32 colId, NScheme::TTypeInfo type, i32 keyOrder = -1)
+ TTableColumnInfo(TString name, ui32 colId, NScheme::TTypeInfo type, const TString& typeMod = {}, i32 keyOrder = -1)
: Name(name)
, Id(colId)
, PType(type)
+ , PTypeMod(typeMod)
, KeyOrder(keyOrder)
{}
};
@@ -118,8 +120,8 @@ struct TSysTables {
auto type = NScheme::TTypeInfo(NScheme::TUint64::TypeId);
auto typeUi32 = NScheme::TTypeInfo(NScheme::TUint32::TypeId);
- columns[0] = TTableColumnInfo(GetColName(EColumns::LockId), (ui32)EColumns::LockId, type, 0);
- columns[1] = TTableColumnInfo(GetColName(EColumns::DataShard), (ui32)EColumns::DataShard, type, 1);
+ columns[0] = TTableColumnInfo(GetColName(EColumns::LockId), (ui32)EColumns::LockId, type, "", 0);
+ columns[1] = TTableColumnInfo(GetColName(EColumns::DataShard), (ui32)EColumns::DataShard, type, "", 1);
columns[2] = TTableColumnInfo(GetColName(EColumns::Generation), (ui32)EColumns::Generation, typeUi32);
columns[3] = TTableColumnInfo(GetColName(EColumns::Counter), (ui32)EColumns::Counter, type);
@@ -127,8 +129,8 @@ struct TSysTables {
keyTypes.push_back(type);
if (v2) {
- columns[4] = TTableColumnInfo(GetColName(EColumns::SchemeShard), (ui32)EColumns::SchemeShard, type, 2);
- columns[5] = TTableColumnInfo(GetColName(EColumns::PathId), (ui32)EColumns::PathId, type, 3);
+ columns[4] = TTableColumnInfo(GetColName(EColumns::SchemeShard), (ui32)EColumns::SchemeShard, type, "", 2);
+ columns[5] = TTableColumnInfo(GetColName(EColumns::PathId), (ui32)EColumns::PathId, type, "", 3);
keyTypes.push_back(type);
keyTypes.push_back(type);
}
diff --git a/ydb/core/tx/scheme_board/cache.cpp b/ydb/core/tx/scheme_board/cache.cpp
index b0c7b7fe857..e0ab9b6470f 100644
--- a/ydb/core/tx/scheme_board/cache.cpp
+++ b/ydb/core/tx/scheme_board/cache.cpp
@@ -746,8 +746,11 @@ class TSchemeCache: public TMonitorableActor<TSchemeCache> {
auto& column = Columns[columnDesc.GetId()];
column.Id = columnDesc.GetId();
column.Name = columnDesc.GetName();
- column.PType = NScheme::TypeInfoFromProtoColumnType(columnDesc.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(columnDesc.GetTypeId(),
columnDesc.HasTypeInfo() ? &columnDesc.GetTypeInfo() : nullptr);
+ column.PType = typeInfoMod.TypeInfo;
+ column.PTypeMod = typeInfoMod.TypeMod;
+
if (columnDesc.GetNotNull()) {
NotNullColumns.insert(columnDesc.GetName());
}
@@ -807,8 +810,10 @@ class TSchemeCache: public TMonitorableActor<TSchemeCache> {
auto& column = Columns[columnDesc.GetId()];
column.Id = columnDesc.GetId();
column.Name = columnDesc.GetName();
- column.PType = NScheme::TypeInfoFromProtoColumnType(columnDesc.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(columnDesc.GetTypeId(),
columnDesc.HasTypeInfo() ? &columnDesc.GetTypeInfo() : nullptr);
+ column.PType = typeInfoMod.TypeInfo;
+ column.PTypeMod = typeInfoMod.TypeMod;
nameToId[column.Name] = column.Id;
if (columnDesc.GetNotNull()) {
NotNullColumns.insert(columnDesc.GetName());
diff --git a/ydb/core/tx/schemeshard/schemeshard__init.cpp b/ydb/core/tx/schemeshard/schemeshard__init.cpp
index 78524389b70..d2972a87cbd 100644
--- a/ydb/core/tx/schemeshard/schemeshard__init.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__init.cpp
@@ -388,7 +388,7 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
return true;
}
- typedef std::tuple<TPathId, ui32, TString, NScheme::TTypeInfo, ui32, ui64, ui64, ui32, ETableColumnDefaultKind, TString, bool> TColumnRec;
+ typedef std::tuple<TPathId, ui32, TString, NScheme::TTypeInfo, TString, ui32, ui64, ui64, ui32, ETableColumnDefaultKind, TString, bool> TColumnRec;
typedef TDeque<TColumnRec> TColumnRows;
bool LoadColumns(NIceDb::TNiceDb& db, TColumnRows& columnRows) const {
@@ -413,17 +413,18 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
auto defaultValue = rowSet.GetValue<Schema::Columns::DefaultValue>();
auto notNull = rowSet.GetValueOrDefault<Schema::Columns::NotNull>(false);
- NScheme::TTypeInfo typeInfo;
+ NScheme::TTypeInfoMod typeInfoMod;
if (typeData) {
NKikimrProto::TTypeInfo protoType;
Y_VERIFY(ParseFromStringNoSizeLimit(protoType, typeData));
- typeInfo = NScheme::TypeInfoFromProtoColumnType(typeId, &protoType);
+ typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(typeId, &protoType);
} else {
- typeInfo = NScheme::TTypeInfo(typeId);
+ typeInfoMod.TypeInfo = NScheme::TTypeInfo(typeId);
}
columnRows.emplace_back(pathId, colId,
- colName, typeInfo, keyOrder, createVersion, deleteVersion,
+ colName, typeInfoMod.TypeInfo, typeInfoMod.TypeMod,
+ keyOrder, createVersion, deleteVersion,
family, defaultKind, defaultValue, notNull);
if (!rowSet.Next()) {
@@ -455,17 +456,18 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
auto defaultValue = rowSet.GetValue<Schema::MigratedColumns::DefaultValue>();
auto notNull = rowSet.GetValueOrDefault<Schema::MigratedColumns::NotNull>(false);
- NScheme::TTypeInfo typeInfo;
+ NScheme::TTypeInfoMod typeInfoMod;
if (typeData) {
NKikimrProto::TTypeInfo protoType;
Y_VERIFY(ParseFromStringNoSizeLimit(protoType, typeData));
- typeInfo = NScheme::TypeInfoFromProtoColumnType(typeId, &protoType);
+ typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(typeId, &protoType);
} else {
- typeInfo = NScheme::TTypeInfo(typeId);
+ typeInfoMod.TypeInfo = NScheme::TTypeInfo(typeId);
}
columnRows.emplace_back(pathId, colId,
- colName, typeInfo, keyOrder, createVersion, deleteVersion,
+ colName, typeInfoMod.TypeInfo, typeInfoMod.TypeMod,
+ keyOrder, createVersion, deleteVersion,
family, defaultKind, defaultValue, notNull);
if (!rowSet.Next()) {
@@ -499,17 +501,18 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
auto defaultValue = rowSet.GetValue<Schema::ColumnAlters::DefaultValue>();
auto notNull = rowSet.GetValueOrDefault<Schema::ColumnAlters::NotNull>(false);
- NScheme::TTypeInfo typeInfo;
+ NScheme::TTypeInfoMod typeInfoMod;
if (typeData) {
NKikimrProto::TTypeInfo protoType;
Y_VERIFY(ParseFromStringNoSizeLimit(protoType, typeData));
- typeInfo = NScheme::TypeInfoFromProtoColumnType(typeId, &protoType);
+ typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(typeId, &protoType);
} else {
- typeInfo = NScheme::TTypeInfo(typeId);
+ typeInfoMod.TypeInfo = NScheme::TTypeInfo(typeId);
}
columnRows.emplace_back(pathId, colId,
- colName, typeInfo, keyOrder, createVersion, deleteVersion,
+ colName, typeInfoMod.TypeInfo, typeInfoMod.TypeMod,
+ keyOrder, createVersion, deleteVersion,
family, defaultKind, defaultValue, notNull);
if (!rowSet.Next()) {
@@ -541,17 +544,18 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
auto defaultValue = rowSet.GetValue<Schema::MigratedColumnAlters::DefaultValue>();
auto notNull = rowSet.GetValueOrDefault<Schema::MigratedColumnAlters::NotNull>(false);
- NScheme::TTypeInfo typeInfo;
+ NScheme::TTypeInfoMod typeInfoMod;
if (typeData) {
NKikimrProto::TTypeInfo protoType;
Y_VERIFY(ParseFromStringNoSizeLimit(protoType, typeData));
- typeInfo = NScheme::TypeInfoFromProtoColumnType(typeId, &protoType);
+ typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(typeId, &protoType);
} else {
- typeInfo = NScheme::TTypeInfo(typeId);
+ typeInfoMod.TypeInfo = NScheme::TTypeInfo(typeId);
}
columnRows.emplace_back(pathId, colId,
- colName, typeInfo, keyOrder, createVersion, deleteVersion,
+ colName, typeInfoMod.TypeInfo, typeInfoMod.TypeMod,
+ keyOrder, createVersion, deleteVersion,
family, defaultKind, defaultValue, notNull);
if (!rowSet.Next()) {
@@ -1919,19 +1923,20 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
ui32 colId = std::get<1>(rec);
TString colName = std::get<2>(rec);
NScheme::TTypeInfo typeInfo = std::get<3>(rec);
- ui32 keyOrder = std::get<4>(rec);
- ui64 createVersion = std::get<5>(rec);
- ui64 deleteVersion = std::get<6>(rec);
- ui32 family = std::get<7>(rec);
- auto defaultKind = std::get<8>(rec);
- auto defaultValue = std::get<9>(rec);
- auto notNull = std::get<10>(rec);
+ TString typeMod = std::get<4>(rec);
+ ui32 keyOrder = std::get<5>(rec);
+ ui64 createVersion = std::get<6>(rec);
+ ui64 deleteVersion = std::get<7>(rec);
+ ui32 family = std::get<8>(rec);
+ auto defaultKind = std::get<9>(rec);
+ auto defaultValue = std::get<10>(rec);
+ auto notNull = std::get<11>(rec);
Y_VERIFY_S(Self->PathsById.contains(pathId), "Path doesn't exist, pathId: " << pathId);
Y_VERIFY_S(Self->PathsById.at(pathId)->IsTable() || Self->PathsById.at(pathId)->IsExternalTable(), "Path is not a table or external table, pathId: " << pathId);
Y_VERIFY_S(Self->Tables.FindPtr(pathId) || Self->ExternalTables.FindPtr(pathId), "Table or external table don't exist, pathId: " << pathId);
- TTableInfo::TColumn colInfo(colName, colId, typeInfo);
+ TTableInfo::TColumn colInfo(colName, colId, typeInfo, typeMod);
colInfo.KeyOrder = keyOrder;
colInfo.CreateVersion = createVersion;
colInfo.DeleteVersion = deleteVersion;
@@ -1976,13 +1981,14 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
ui32 colId = std::get<1>(rec);
TString colName = std::get<2>(rec);
NScheme::TTypeInfo typeInfo = std::get<3>(rec);
- ui32 keyOrder = std::get<4>(rec);
- ui64 createVersion = std::get<5>(rec);
- ui64 deleteVersion = std::get<6>(rec);
- ui32 family = std::get<7>(rec);
- auto defaultKind = std::get<8>(rec);
- auto defaultValue = std::get<9>(rec);
- auto notNull = std::get<10>(rec);
+ TString typeMod = std::get<4>(rec);
+ ui32 keyOrder = std::get<5>(rec);
+ ui64 createVersion = std::get<6>(rec);
+ ui64 deleteVersion = std::get<7>(rec);
+ ui32 family = std::get<8>(rec);
+ auto defaultKind = std::get<9>(rec);
+ auto defaultValue = std::get<10>(rec);
+ auto notNull = std::get<11>(rec);
Y_VERIFY_S(Self->PathsById.contains(pathId), "Path doesn't exist, pathId: " << pathId);
Y_VERIFY_S(Self->PathsById.at(pathId)->IsTable(), "Path is not a table, pathId: " << pathId);
@@ -1995,7 +2001,7 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
tableInfo->AlterData->NextColumnId = colId + 1; // calc next NextColumnId
}
- TTableInfo::TColumn colInfo(colName, colId, typeInfo);
+ TTableInfo::TColumn colInfo(colName, colId, typeInfo, typeMod);
colInfo.KeyOrder = keyOrder;
colInfo.CreateVersion = createVersion;
colInfo.DeleteVersion = deleteVersion;
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_olap_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_olap_table.cpp
index 2ceee89224f..1cf1c24aa1d 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_olap_table.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_olap_table.cpp
@@ -96,9 +96,9 @@ TColumnTableInfo::TPtr ParseParams(
for (const auto& col : tableSchema->GetColumns()) {
ui32 id = col.GetId();
TString name = col.GetName();
- auto typeInfo = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
- columns[id] = TOlapSchema::TColumn{id, name, typeInfo, Max<ui32>()};
+ columns[id] = TOlapSchema::TColumn{id, name, typeInfoMod.TypeInfo, Max<ui32>()};
columnsByName[name] = id;
// TODO: add checks for compatibility with new schema after we allow such changes
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_create_cdc_stream.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_create_cdc_stream.cpp
index de9d29af56c..95c1c2f32ec 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_create_cdc_stream.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_create_cdc_stream.cpp
@@ -740,7 +740,7 @@ TVector<ISubOperationBase::TPtr> CreateNewCdcStream(TOperationId opId, const TTx
auto& keyComponent = *pqConfig.AddPartitionKeySchema();
keyComponent.SetName(column.Name);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.PType, column.PTypeMod);
keyComponent.SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*keyComponent.MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_create_external_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_create_external_table.cpp
index 7621265af9a..1da1e4eacf0 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_create_external_table.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_create_external_table.cpp
@@ -93,7 +93,7 @@ TExternalTableInfo::TPtr CreateExternalTable(const NKikimrSchemeOp::TExternalTab
nextColumnId = colId + 1 > nextColumnId ? colId + 1 : nextColumnId;
TTableInfo::TColumn& column = externalTableInfo->Columns[colId];
- column = TTableInfo::TColumn(colName, colId, typeInfo);
+ column = TTableInfo::TColumn(colName, colId, typeInfo, ""); // TODO: do we need typeMod here?
column.NotNull = col.GetNotNull();
}
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp
index c2317e4661e..290b39106e7 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp
@@ -112,7 +112,7 @@ bool DoInitPartitioning(TTableInfo::TPtr tableInfo,
if (!IsAllowedKeyType(type)) {
errStr = Sprintf("Column %s has wrong key type %s",
- tableInfo->Columns[ki].Name.c_str(), NScheme::TypeName(type));
+ tableInfo->Columns[ki].Name.c_str(), NScheme::TypeName(type).c_str());
return false;
}
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_upgrade_subdomain.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_upgrade_subdomain.cpp
index 9f67b76510c..48ade77c5aa 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_upgrade_subdomain.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_upgrade_subdomain.cpp
@@ -220,7 +220,7 @@ public:
auto colDescr = descr.AddColumns();
colDescr->SetId(columnId);
colDescr->SetName(column.Name);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.PType, column.PTypeMod);
colDescr->SetColType(columnType.TypeId);
if (columnType.TypeInfo) {
*colDescr->MutableColTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp
index 5f807a5cfff..aebd5be3062 100644
--- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp
@@ -2376,7 +2376,7 @@ void TSchemeShard::PersistTableAltered(NIceDb::TNiceDb& db, const TPathId pathId
ui32 colId = col.first;
const TTableInfo::TColumn& cinfo = col.second;
TString typeData;
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(cinfo.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(cinfo.PType, cinfo.PTypeMod);
if (columnType.TypeInfo) {
Y_VERIFY(columnType.TypeInfo->SerializeToString(&typeData));
}
@@ -2434,7 +2434,7 @@ void TSchemeShard::PersistAddAlterTable(NIceDb::TNiceDb& db, TPathId pathId, con
ui32 colId = col.first;
const TTableInfo::TColumn& cinfo = col.second;
TString typeData;
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(cinfo.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(cinfo.PType, cinfo.PTypeMod);
if (columnType.TypeInfo) {
Y_VERIFY(columnType.TypeInfo->SerializeToString(&typeData));
}
@@ -2575,7 +2575,7 @@ void TSchemeShard::PersistExternalTable(NIceDb::TNiceDb &db, TPathId pathId, con
ui32 colId = col.first;
const TTableInfo::TColumn& cinfo = col.second;
TString typeData;
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(cinfo.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(cinfo.PType, cinfo.PTypeMod);
if (columnType.TypeInfo) {
Y_VERIFY(columnType.TypeInfo->SerializeToString(&typeData));
}
@@ -5944,7 +5944,7 @@ TString TSchemeShard::FillAlterTableTxBody(TPathId pathId, TShardIdx shardIdx, T
auto descr = proto->AddDropColumns();
descr->SetName(colInfo.Name);
descr->SetId(colInfo.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(colInfo.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(colInfo.PType, colInfo.PTypeMod);
descr->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*descr->MutableTypeInfo() = *columnType.TypeInfo;
@@ -5953,7 +5953,7 @@ TString TSchemeShard::FillAlterTableTxBody(TPathId pathId, TShardIdx shardIdx, T
auto descr = proto->AddColumns();
descr->SetName(colInfo.Name);
descr->SetId(colInfo.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(colInfo.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(colInfo.PType, colInfo.PTypeMod);
descr->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*descr->MutableTypeInfo() = *columnType.TypeInfo;
@@ -6137,6 +6137,7 @@ void TSchemeShard::FillTableDescription(TPathId tableId, ui32 partitionIdx, ui64
}
bool TSchemeShard::FillUniformPartitioning(TVector<TString>& rangeEnds, ui32 keySize, NScheme::TTypeInfo firstKeyColType, ui32 partitionCount, const NScheme::TTypeRegistry* typeRegistry, TString& errStr) {
+ Y_UNUSED(typeRegistry);
if (partitionCount > 1) {
// RangeEnd key will have first cell with non-NULL value and rest of the cells with NULLs
TVector<TCell> rangeEnd(keySize);
@@ -6155,7 +6156,7 @@ bool TSchemeShard::FillUniformPartitioning(TVector<TString>& rangeEnds, ui32 key
valSz = 8;
break;
default:
- errStr = TStringBuilder() << "Unsupported first key column type " << typeRegistry->GetTypeName(typeId) << ", only Uint32 and Uint64 are supported";
+ errStr = TStringBuilder() << "Unsupported first key column type " << NScheme::TypeName(firstKeyColType) << ", only Uint32 and Uint64 are supported";
return false;
}
diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.cpp b/ydb/core/tx/schemeshard/schemeshard_info_types.cpp
index 5366f47b72e..e5c75e9e907 100644
--- a/ydb/core/tx/schemeshard/schemeshard_info_types.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard_info_types.cpp
@@ -123,6 +123,7 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData(
}
NScheme::TTypeInfo typeInfo;
+ TString typeMod;
if (type) {
// Only allow YQL types
if (!NScheme::NTypeIds::IsYqlType(type->GetTypeId())) {
@@ -137,6 +138,7 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData(
return nullptr;
}
typeInfo = NScheme::TTypeInfo(NScheme::NTypeIds::Pg, typeDesc);
+ typeMod = NPg::TypeModFromPgTypeName(typeName);
}
ui32 colId = col.HasId() ? col.GetId() : alterData->NextColumnId;
@@ -154,7 +156,7 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData(
colName2Id[colName] = colId;
TTableInfo::TColumn& column = alterData->Columns[colId];
- column = TTableInfo::TColumn(colName, colId, typeInfo);
+ column = TTableInfo::TColumn(colName, colId, typeInfo, typeMod);
column.Family = columnFamily ? columnFamily->GetId() : 0;
column.NotNull = col.GetNotNull();
if (source)
@@ -319,7 +321,7 @@ TVector<ui32> TTableInfo::FillDescriptionCache(TPathElement::TPtr pathInfo) {
auto colDescr = TableDescription.AddColumns();
colDescr->SetName(column.Name);
colDescr->SetId(column.Id);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.PType, column.PTypeMod);
colDescr->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*colDescr->MutableTypeInfo() = *columnType.TypeInfo;
@@ -2045,7 +2047,7 @@ bool TOlapSchema::UpdateProto(NKikimrSchemeOp::TColumnTableSchema& proto, TStrin
#endif
}
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(typeInfo);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(typeInfo, "");
colProto.SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*colProto.MutableTypeInfo() = *columnType.TypeInfo;
@@ -2155,7 +2157,8 @@ bool TOlapSchema::Parse(const NKikimrSchemeOp::TColumnTableSchema& proto, TStrin
}
if (colProto.HasTypeInfo()) {
- col.Type = NScheme::TypeInfoFromProtoColumnType(colProto.GetTypeId(), &colProto.GetTypeInfo());
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(colProto.GetTypeId(), &colProto.GetTypeInfo());
+ col.Type = typeInfoMod.TypeInfo;
} else {
col.Type = NScheme::TTypeInfo(colProto.GetTypeId());
}
@@ -2327,8 +2330,9 @@ TOlapStoreInfo::TOlapStoreInfo(
auto& col = preset.Columns[colProto.GetId()];
col.Id = colProto.GetId();
col.Name = colProto.GetName();
- col.Type = NScheme::TypeInfoFromProtoColumnType(colProto.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(colProto.GetTypeId(),
colProto.HasTypeInfo() ? &colProto.GetTypeInfo() : nullptr);
+ col.Type = typeInfoMod.TypeInfo;
preset.ColumnsByName[col.Name] = col.Id;
}
for (const auto& keyName : presetProto.GetSchema().GetKeyColumnNames()) {
diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.h b/ydb/core/tx/schemeshard/schemeshard_info_types.h
index b156aee3658..9dbf42fa513 100644
--- a/ydb/core/tx/schemeshard/schemeshard_info_types.h
+++ b/ydb/core/tx/schemeshard/schemeshard_info_types.h
@@ -315,8 +315,8 @@ struct TTableInfo : public TSimpleRefCount<TTableInfo> {
TString DefaultValue;
bool NotNull = false;
- TColumn(const TString& name, ui32 id, NScheme::TTypeInfo type)
- : NTable::TScheme::TColumn(name, id, type)
+ TColumn(const TString& name, ui32 id, NScheme::TTypeInfo type, const TString& typeMod)
+ : NTable::TScheme::TColumn(name, id, type, typeMod)
, CreateVersion(0)
, DeleteVersion(Max<ui64>())
{}
diff --git a/ydb/core/tx/schemeshard/schemeshard_path_describer.cpp b/ydb/core/tx/schemeshard/schemeshard_path_describer.cpp
index bb04164791b..f98fab70c6b 100644
--- a/ydb/core/tx/schemeshard/schemeshard_path_describer.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard_path_describer.cpp
@@ -779,7 +779,8 @@ void TPathDescriber::DescribeBlobDepot(const TPath& path) {
}
void TPathDescriber::DescribeExternalTable(const TActorContext& ctx, TPathId pathId, TPathElement::TPtr pathEl) {
- const NScheme::TTypeRegistry* typeRegistry = AppData(ctx)->TypeRegistry;
+ Y_UNUSED(ctx);
+
auto it = Self->ExternalTables.FindPtr(pathId);
Y_VERIFY(it, "ExternalTable is not found");
TExternalTableInfo::TPtr externalTableInfo = *it;
@@ -800,8 +801,8 @@ void TPathDescriber::DescribeExternalTable(const TActorContext& ctx, TPathId pat
auto colDescr = entry->AddColumns();
colDescr->SetName(cinfo.Name);
- colDescr->SetType(typeRegistry->GetTypeName(cinfo.PType.GetTypeId())); // TODO: no pg type details in string type
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(cinfo.PType);
+ colDescr->SetType(NScheme::TypeName(cinfo.PType, cinfo.PTypeMod));
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(cinfo.PType, cinfo.PTypeMod);
colDescr->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*colDescr->MutableTypeInfo() = *columnType.TypeInfo;
@@ -982,6 +983,7 @@ THolder<TEvSchemeShard::TEvDescribeSchemeResultBuilder> DescribePath(
void TSchemeShard::DescribeTable(const TTableInfo::TPtr tableInfo, const NScheme::TTypeRegistry* typeRegistry,
bool fillConfig, bool fillBoundaries, NKikimrSchemeOp::TTableDescription* entry) const
{
+ Y_UNUSED(typeRegistry);
THashMap<ui32, TString> familyNames;
bool familyNamesBuilt = false;
@@ -994,8 +996,8 @@ void TSchemeShard::DescribeTable(const TTableInfo::TPtr tableInfo, const NScheme
auto colDescr = entry->AddColumns();
colDescr->SetName(cinfo.Name);
- colDescr->SetType(typeRegistry->GetTypeName(cinfo.PType.GetTypeId())); // TODO: no pg type details in string type
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(cinfo.PType);
+ colDescr->SetType(NScheme::TypeName(cinfo.PType, cinfo.PTypeMod));
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(cinfo.PType, cinfo.PTypeMod);
colDescr->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*colDescr->MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/schemeshard/schemeshard_utils.cpp b/ydb/core/tx/schemeshard/schemeshard_utils.cpp
index 23241b143a4..84c6fd44d86 100644
--- a/ydb/core/tx/schemeshard/schemeshard_utils.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard_utils.cpp
@@ -295,8 +295,6 @@ NKikimrSchemeOp::TTableDescription CalcImplTableDesc(
implKeyToImplColumn[implTableColumns.Keys[keyId]] = keyId;
}
- const TAppData* appData = AppData();
-
result.ClearColumns();
for (auto& iter: baseTableInfo->Columns) {
const NSchemeShard::TTableInfo::TColumn& column = iter.second;
@@ -307,11 +305,7 @@ NKikimrSchemeOp::TTableDescription CalcImplTableDesc(
if (implTableColumns.Columns.contains(column.Name)) {
auto item = result.AddColumns();
item->SetName(column.Name);
-
- // TODO: support pg types
- Y_VERIFY(column.PType.GetTypeId() != NScheme::NTypeIds::Pg);
- item->SetType(appData->TypeRegistry->GetTypeName(column.PType.GetTypeId()));
-
+ item->SetType(NScheme::TypeName(column.PType, column.PTypeMod));
ui32 order = Max<ui32>();
if (implKeyToImplColumn.contains(column.Name)) {
order = implKeyToImplColumn.at(column.Name);
diff --git a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp
index a47cebcf4a9..f2918d23027 100644
--- a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp
+++ b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp
@@ -434,8 +434,9 @@ void CheckBoundaries(const NKikimrScheme::TEvDescribeSchemeResult &record) {
const NKikimrSchemeOp::TPathDescription& descr = record.GetPathDescription();
THashMap<ui32, NScheme::TTypeInfo> colTypes;
for (const auto& col : descr.GetTable().GetColumns()) {
- colTypes[col.GetId()] = NScheme::TypeInfoFromProtoColumnType(col.GetTypeId(),
+ auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(col.GetTypeId(),
col.HasTypeInfo() ? &col.GetTypeInfo() : nullptr);
+ colTypes[col.GetId()] = typeInfoMod.TypeInfo;
}
TVector<NScheme::TTypeInfo> keyColTypes;
for (const auto& ki : descr.GetTable().GetKeyColumnIds()) {
diff --git a/ydb/core/tx/tx_proxy/datareq.cpp b/ydb/core/tx/tx_proxy/datareq.cpp
index 41fe51828ed..90444545da3 100644
--- a/ydb/core/tx/tx_proxy/datareq.cpp
+++ b/ydb/core/tx/tx_proxy/datareq.cpp
@@ -1162,7 +1162,7 @@ void TDataReq::ProcessReadTableResolve(NSchemeCache::TSchemeCacheRequest *cacheR
auto &c = *tx.AddColumns();
c.SetId(col.Id);
c.SetName(col.Name);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(col.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(col.PType, col.PTypeMod);
c.SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*c.MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/tx_proxy/describe.cpp b/ydb/core/tx/tx_proxy/describe.cpp
index ba4b6305065..4d179a53436 100644
--- a/ydb/core/tx/tx_proxy/describe.cpp
+++ b/ydb/core/tx/tx_proxy/describe.cpp
@@ -103,9 +103,8 @@ class TDescribeReq : public TActor<TDescribeReq> {
for (const auto& [id, column] : entry.Columns) {
auto* col = table->AddColumns();
col->SetName(column.Name);
- // TODO: support pg types (name)
- col->SetType(AppData(ctx)->TypeRegistry->GetTypeName(column.PType.GetTypeId()));
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(column.PType);
+ col->SetType(NScheme::TypeName(column.PType, column.PTypeMod));
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.PType, column.PTypeMod);
col->SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*col->MutableTypeInfo() = *columnType.TypeInfo;
diff --git a/ydb/core/tx/tx_proxy/read_table_impl.cpp b/ydb/core/tx/tx_proxy/read_table_impl.cpp
index b19a85de34b..f05e344c7bb 100644
--- a/ydb/core/tx/tx_proxy/read_table_impl.cpp
+++ b/ydb/core/tx/tx_proxy/read_table_impl.cpp
@@ -1433,7 +1433,7 @@ private:
auto &c = *tx.AddColumns();
c.SetId(col.Id);
c.SetName(col.Name);
- auto columnType = NScheme::ProtoColumnTypeFromTypeInfo(col.PType);
+ auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(col.PType, col.PTypeMod);
c.SetTypeId(columnType.TypeId);
if (columnType.TypeInfo) {
*c.MutableTypeInfo() = *columnType.TypeInfo;
@@ -1731,8 +1731,10 @@ private:
meta->set_name(col.Name);
if (col.PType.GetTypeId() == NScheme::NTypeIds::Pg) {
- auto pgType = meta->mutable_type()->mutable_pg_type();
- pgType->set_oid(NPg::PgTypeIdFromTypeDesc(col.PType.GetTypeDesc()));
+ auto* typeDesc = col.PType.GetTypeDesc();
+ auto* pg = meta->mutable_type()->mutable_pg_type();
+ pg->set_type_name(NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_oid(NPg::PgTypeIdFromTypeDesc(typeDesc));
} else {
auto id = static_cast<NYql::NProto::TypeIds>(col.PType.GetTypeId());
if (id == NYql::NProto::Decimal) {
diff --git a/ydb/core/tx/tx_proxy/upload_rows_common_impl.h b/ydb/core/tx/tx_proxy/upload_rows_common_impl.h
index 19260691b0e..a9acdd64e2e 100644
--- a/ydb/core/tx/tx_proxy/upload_rows_common_impl.h
+++ b/ydb/core/tx/tx_proxy/upload_rows_common_impl.h
@@ -137,6 +137,7 @@ protected:
TString ColName;
ui32 PositionInStruct;
NScheme::TTypeInfo Type;
+ i32 Typmod;
bool NotNull = false;
};
TVector<TString> KeyColumnNames;
@@ -335,13 +336,15 @@ private:
if (!errorMessage.empty()) {
return false;
} else if (reqColumns.empty()) {
- for (auto& [name, type] : SrcColumns) {
+ for (auto& [name, typeInfo] : SrcColumns) {
Ydb::Type ydbType;
- if (type.GetTypeId() == NScheme::NTypeIds::Pg) {
- Ydb::PgType* pgType = ydbType.mutable_pg_type();
- pgType->set_oid(NPg::PgTypeIdFromTypeDesc(type.GetTypeDesc()));
+ if (typeInfo.GetTypeId() != NScheme::NTypeIds::Pg) {
+ ydbType.set_type_id((Ydb::Type::PrimitiveTypeId)typeInfo.GetTypeId());
} else {
- ydbType.set_type_id((Ydb::Type::PrimitiveTypeId)type.GetTypeId());
+ auto* typeDesc = typeInfo.GetTypeDesc();
+ auto* pg = ydbType.mutable_pg_type();
+ pg->set_type_name(NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_oid(NPg::PgTypeIdFromTypeDesc(typeDesc));
}
reqColumns.emplace_back(name, std::move(ydbType));
}
@@ -354,6 +357,7 @@ private:
errorMessage = Sprintf("Unknown column: %s", name.c_str());
return false;
}
+ i32 typmod = -1;
ui32 colId = *cp;
auto& ci = *entry.Columns.FindPtr(colId);
@@ -364,8 +368,8 @@ private:
bool ok = SameDstType(typeInRequest, ci.PType, GetSourceType() != EUploadSource::ProtoValues);
if (!ok) {
errorMessage = Sprintf("Type mismatch for column %s: expected %s, got %s",
- name.c_str(), NScheme::TypeName(ci.PType),
- NScheme::TypeName(typeInRequest));
+ name.c_str(), NScheme::TypeName(ci.PType).c_str(),
+ NScheme::TypeName(typeInRequest).c_str());
return false;
}
} else if (typeInProto.has_decimal_type() && ci.PType.GetTypeId() == NScheme::NTypeIds::Decimal) {
@@ -380,24 +384,34 @@ private:
return false;
}
} else if (typeInProto.has_pg_type()) {
- auto pgTypeId = typeInProto.pg_type().oid();
- auto* typeDesc = NPg::TypeDescFromPgTypeId(pgTypeId);
+ const auto& typeName = typeInProto.pg_type().type_name();
+ auto* typeDesc = NPg::TypeDescFromPgTypeName(typeName);
if (!typeDesc) {
- errorMessage = Sprintf("Unknown pg type for column %s: %u",
- name.c_str(), pgTypeId);
+ errorMessage = Sprintf("Unknown pg type for column %s: %s",
+ name.c_str(), typeName.c_str());
return false;
}
auto typeInRequest = NScheme::TTypeInfo(NScheme::NTypeIds::Pg, typeDesc);
bool ok = SameDstType(typeInRequest, ci.PType, false);
if (!ok) {
errorMessage = Sprintf("Type mismatch for column %s: expected %s, got %s",
- name.c_str(), NScheme::TypeName(ci.PType),
- NScheme::TypeName(typeInRequest));
+ name.c_str(), NScheme::TypeName(ci.PType).c_str(),
+ NScheme::TypeName(typeInRequest).c_str());
return false;
}
+ if (!ci.PTypeMod.empty() && NPg::TypeDescNeedsCoercion(typeDesc)) {
+ auto result = NPg::BinaryTypeModFromTextTypeMod(ci.PTypeMod, typeDesc);
+ if (result.Error) {
+ errorMessage = Sprintf("Invalid typemod for column %s: type %s, error %s",
+ name.c_str(), NScheme::TypeName(ci.PType, ci.PTypeMod).c_str(),
+ result.Error->c_str());
+ return false;
+ }
+ typmod = result.Typmod;
+ }
} else {
errorMessage = Sprintf("Unexpected type for column %s: expected %s",
- name.c_str(), NScheme::TypeName(ci.PType));
+ name.c_str(), NScheme::TypeName(ci.PType).c_str());
return false;
}
@@ -407,11 +421,11 @@ private:
}
if (ci.KeyOrder != -1) {
- KeyColumnPositions[ci.KeyOrder] = TFieldDescription{ci.Id, ci.Name, (ui32)pos, ci.PType, notNull};
+ KeyColumnPositions[ci.KeyOrder] = TFieldDescription{ci.Id, ci.Name, (ui32)pos, ci.PType, typmod, notNull};
keyColumnsLeft.erase(ci.Name);
KeyColumnNames[ci.KeyOrder] = ci.Name;
} else {
- ValueColumnPositions.emplace_back(TFieldDescription{ci.Id, ci.Name, (ui32)pos, ci.PType, notNull});
+ ValueColumnPositions.emplace_back(TFieldDescription{ci.Id, ci.Name, (ui32)pos, ci.PType, typmod, notNull});
ValueColumnNames.emplace_back(ci.Name);
ValueColumnTypes.emplace_back(ci.PType);
}
diff --git a/ydb/core/ydb_convert/table_description.cpp b/ydb/core/ydb_convert/table_description.cpp
index 435ce40153f..62a4044ec3f 100644
--- a/ydb/core/ydb_convert/table_description.cpp
+++ b/ydb/core/ydb_convert/table_description.cpp
@@ -35,29 +35,40 @@ static void FillStoragePool(TStoragePoolHolder* out, TAddStoragePoolFunc<TStorag
template <typename TColumn>
static Ydb::Type* AddColumn(Ydb::Table::ColumnMeta* newColumn, const TColumn& column) {
- NYql::NProto::TypeIds protoType;
- if (!NYql::NProto::TypeIds_Parse(column.GetType(), &protoType)) {
- throw NYql::TErrorException(NKikimrIssues::TIssuesIds::DEFAULT_ERROR)
- << "Got invalid type: " << column.GetType() << " for column: " << column.GetName();
- }
-
newColumn->set_name(column.GetName());
Ydb::Type* columnType = nullptr;
- if (column.GetNotNull() || protoType == NScheme::NTypeIds::Pg) {
+ auto* typeDesc = NPg::TypeDescFromPgTypeName(column.GetType());
+ if (typeDesc) {
columnType = newColumn->mutable_type();
+ auto* pg = columnType->mutable_pg_type();
+ pg->set_type_name(NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_type_modifier(NPg::TypeModFromPgTypeName(column.GetType()));
+ pg->set_oid(NPg::PgTypeIdFromTypeDesc(typeDesc));
+ pg->set_typlen(0);
+ pg->set_typmod(0);
} else {
- columnType = newColumn->mutable_type()->mutable_optional_type()->mutable_item();
- }
+ NYql::NProto::TypeIds protoType;
+ if (!NYql::NProto::TypeIds_Parse(column.GetType(), &protoType)) {
+ throw NYql::TErrorException(NKikimrIssues::TIssuesIds::DEFAULT_ERROR)
+ << "Got invalid type: " << column.GetType() << " for column: " << column.GetName();
+ }
- Y_ENSURE(columnType);
- if (protoType == NYql::NProto::TypeIds::Decimal) {
- auto typeParams = columnType->mutable_decimal_type();
- // TODO: Change TEvDescribeSchemeResult to return decimal params
- typeParams->set_precision(22);
- typeParams->set_scale(9);
- } else {
- NMiniKQL::ExportPrimitiveTypeToProto(protoType, *columnType);
+ if (column.GetNotNull()) {
+ columnType = newColumn->mutable_type();
+ } else {
+ columnType = newColumn->mutable_type()->mutable_optional_type()->mutable_item();
+ }
+
+ Y_ENSURE(columnType);
+ if (protoType == NYql::NProto::TypeIds::Decimal) {
+ auto typeParams = columnType->mutable_decimal_type();
+ // TODO: Change TEvDescribeSchemeResult to return decimal params
+ typeParams->set_precision(22);
+ typeParams->set_scale(9);
+ } else {
+ NMiniKQL::ExportPrimitiveTypeToProto(protoType, *columnType);
+ }
}
return columnType;
}
@@ -164,7 +175,9 @@ void FillColumnDescription(Ydb::Table::DescribeTableResult& out, const NKikimrSc
}
}
-bool ExtractColumnTypeInfo(NScheme::TTypeInfo& outTypeInfo, const Ydb::Type& inType, Ydb::StatusIds::StatusCode& status, TString& error) {
+bool ExtractColumnTypeInfo(NScheme::TTypeInfo& outTypeInfo, TString& outTypeMod,
+ const Ydb::Type& inType, Ydb::StatusIds::StatusCode& status, TString& error)
+{
ui32 typeId = 0;
auto itemType = inType.has_optional_type() ? inType.optional_type().item() : inType;
switch (itemType.type_case()) {
@@ -192,14 +205,16 @@ bool ExtractColumnTypeInfo(NScheme::TTypeInfo& outTypeInfo, const Ydb::Type& inT
break;
}
case Ydb::Type::kPgType: {
- ui32 pgTypeId = itemType.pg_type().oid();
- auto* desc = NPg::TypeDescFromPgTypeId(pgTypeId);
+ const auto& pgType = itemType.pg_type();
+ const auto& typeName = pgType.type_name();
+ auto* desc = NPg::TypeDescFromPgTypeName(typeName);
if (!desc) {
status = Ydb::StatusIds::BAD_REQUEST;
- error = TStringBuilder() << "Invalid PG typeId: " << pgTypeId;
+ error = TStringBuilder() << "Invalid PG type name: " << typeName;
return false;
}
outTypeInfo = NScheme::TTypeInfo(NScheme::NTypeIds::Pg, desc);
+ outTypeMod = pgType.type_modifier();
return true;
}
@@ -239,10 +254,11 @@ bool FillColumnDescription(NKikimrSchemeOp::TTableDescription& out,
}
NScheme::TTypeInfo typeInfo;
- if (!ExtractColumnTypeInfo(typeInfo, column.type(), status, error)) {
+ TString typeMod;
+ if (!ExtractColumnTypeInfo(typeInfo, typeMod, column.type(), status, error)) {
return false;
}
- cd->SetType(NScheme::TypeName(typeInfo));
+ cd->SetType(NScheme::TypeName(typeInfo, typeMod));
if (!column.family().empty()) {
cd->SetFamilyName(column.family());
diff --git a/ydb/core/ydb_convert/table_description.h b/ydb/core/ydb_convert/table_description.h
index 86d304f62b0..7a7be50aa57 100644
--- a/ydb/core/ydb_convert/table_description.h
+++ b/ydb/core/ydb_convert/table_description.h
@@ -18,7 +18,8 @@ void FillColumnDescription(Ydb::Table::DescribeTableResult& out, const NKikimrSc
// in
bool FillColumnDescription(NKikimrSchemeOp::TTableDescription& out,
const google::protobuf::RepeatedPtrField<Ydb::Table::ColumnMeta>& in, Ydb::StatusIds::StatusCode& status, TString& error);
-bool ExtractColumnTypeInfo(NScheme::TTypeInfo& outTypeInfo, const Ydb::Type& inType, Ydb::StatusIds::StatusCode& status, TString& error);
+bool ExtractColumnTypeInfo(NScheme::TTypeInfo& outTypeInfo, TString& outTypeMod,
+ const Ydb::Type& inType, Ydb::StatusIds::StatusCode& status, TString& error);
// out
void FillTableBoundary(Ydb::Table::DescribeTableResult& out,
diff --git a/ydb/core/yq/libs/result_formatter/result_formatter_ut.cpp b/ydb/core/yq/libs/result_formatter/result_formatter_ut.cpp
index ea6cf3a7d89..8a820b0ff20 100644
--- a/ydb/core/yq/libs/result_formatter/result_formatter_ut.cpp
+++ b/ydb/core/yq/libs/result_formatter/result_formatter_ut.cpp
@@ -526,6 +526,7 @@ Y_UNIT_TEST_SUITE(ResultFormatter) {
auto& column = *rs.add_columns();
column.set_name("column0");
auto& pg_type = *column.mutable_type()->mutable_pg_type();
+ pg_type.set_type_name("pgbool");
pg_type.set_oid(16);
pg_type.set_typlen(234);
pg_type.set_typmod(-987);
diff --git a/ydb/library/mkql_proto/mkql_proto.cpp b/ydb/library/mkql_proto/mkql_proto.cpp
index c1b5abea1d4..38eeba2ba82 100644
--- a/ydb/library/mkql_proto/mkql_proto.cpp
+++ b/ydb/library/mkql_proto/mkql_proto.cpp
@@ -7,6 +7,7 @@
#include <ydb/library/yql/minikql/mkql_type_ops.h>
#include <ydb/library/yql/parser/pg_catalog/catalog.h>
#include <ydb/library/yql/parser/pg_wrapper/interface/codec.h>
+#include <ydb/library/yql/parser/pg_wrapper/interface/type_desc.h>
#include <ydb/library/yql/public/decimal/yql_decimal.h>
#include <ydb/library/yql/minikql/dom/json.h>
#include <ydb/library/yql/utils/utf8.h>
@@ -278,12 +279,17 @@ void ExportTypeToProtoImpl(TType* type, Ydb::Type& res, const TVector<ui32>* col
}
case TType::EKind::Pg: {
- auto pgType = static_cast<TPgType*>(type);
- auto t = res.mutable_pg_type();
- t->set_oid(pgType->GetTypeId());
- t->set_typmod(-1);
+ auto* pgType = static_cast<TPgType*>(type);
+ auto typeId = pgType->GetTypeId();
+ auto* typeDesc = NKikimr::NPg::TypeDescFromPgTypeId(typeId);
+ MKQL_ENSURE(typeDesc, TStringBuilder() << "Unknown PG type id: " << typeId);
+
+ auto* pg = res.mutable_pg_type();
+ pg->set_type_name(NKikimr::NPg::PgTypeNameFromTypeDesc(typeDesc));
+ pg->set_oid(typeId);
+ pg->set_typmod(-1);
const i32 typlen = NYql::NPg::LookupType(pgType->GetTypeId()).TypeLen;
- t->set_typlen(typlen);
+ pg->set_typlen(typlen);
break;
}
@@ -1323,8 +1329,12 @@ TType* TProtoImporter::ImportTypeFromProto(const Ydb::Type& input) {
return env.GetTypeOfEmptyList();
case Ydb::Type::kEmptyDictType:
return env.GetTypeOfEmptyDict();
- case Ydb::Type::kPgType:
- return TPgType::Create(input.pg_type().oid(), env);
+ case Ydb::Type::kPgType: {
+ const auto& typeName = input.pg_type().type_name();
+ auto* typeDesc = NKikimr::NPg::TypeDescFromPgTypeName(typeName);
+ MKQL_ENSURE(typeDesc, TStringBuilder() << "Unknown PG type name: " << typeName);
+ return TPgType::Create(NKikimr::NPg::PgTypeIdFromTypeDesc(typeDesc), env);
+ }
case Ydb::Type::kTypeId: {
MKQL_ENSURE(NUdf::FindDataSlot(input.type_id()), TStringBuilder() << "unknown type id: " << ui32(input.type_id()));
return TDataType::Create(input.type_id(), env);
diff --git a/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp b/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp
index 7e0a7553517..6946d9748be 100644
--- a/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp
+++ b/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp
@@ -15,6 +15,7 @@
#include <ydb/library/yql/public/udf/udf_value_builder.h>
#include <ydb/library/yql/utils/fp_bits.h>
#include <library/cpp/yson/detail.h>
+#include <util/string/split.h>
#define TypeName PG_TypeName
#define SortBy PG_SortBy
@@ -2931,16 +2932,18 @@ void get_type_io_data(Oid typid,
namespace NKikimr::NPg {
+constexpr char INTERNAL_TYPE_AND_MOD_SEPARATOR = ':';
+
class TPgTypeDescriptor
: public NYql::NPg::TTypeDesc
{
public:
explicit TPgTypeDescriptor(const NYql::NPg::TTypeDesc& desc)
: NYql::NPg::TTypeDesc(desc)
- , YdbTypeName(desc.Name + ".pg") // to distinguish from native ydb types (e.g. "int8")
{
if (TypeId == ArrayTypeId) {
const auto& typeDesc = NYql::NPg::LookupType(ElementTypeId);
+ YdbTypeName = TString("_pg") + typeDesc.Name;
if (typeDesc.CompareProcId) {
CompareProcId = NYql::NPg::LookupProc("btarraycmp", { 0, 0 }).ProcId;
}
@@ -2960,10 +2963,14 @@ public:
OutFuncId = NYql::NPg::LookupProc("array_out", { 0 }).ProcId;
}
} else {
+ YdbTypeName = TString("pg") + desc.Name;
StoredSize = TypeLen < 0 ? 0 : TypeLen;
if (TypeId == NAMEOID) {
StoredSize = 0; // store 'name' as usual string
}
+ if (NYql::NPg::HasCast(TypeId, TypeId) && TypeModInFuncId != 0) {
+ NeedsCoercion = true;
+ }
}
}
@@ -3085,7 +3092,7 @@ public:
serialized = (text*)finfo.fn_addr(callInfo);
Y_ENSURE(!callInfo->isnull);
- return {TString(NMiniKQL::GetVarBuf(serialized)), ""};
+ return {TString(NMiniKQL::GetVarBuf(serialized)), {}};
}
PG_CATCH();
{
@@ -3127,7 +3134,7 @@ public:
str = (char*)finfo.fn_addr(callInfo);
Y_ENSURE(!callInfo->isnull);
- return {TString(str), ""};
+ return {TString(str), {}};
}
PG_CATCH();
{
@@ -3141,6 +3148,198 @@ public:
PG_END_TRY();
}
+ TTypeModResult ReadTypeMod(const TString& str) const {
+ TVector<TString> params;
+ ::Split(str, ",", params);
+
+ if (params.size() > 2) {
+ TStringBuilder errMsg;
+ errMsg << "Error in 'typemodin' function: "
+ << NYql::NPg::LookupProc(TypeModInFuncId).Name
+ << ", reason: too many parameters";
+ return {-1, errMsg};
+ }
+
+ TVector<Datum> dvalues;
+ TVector<bool> dnulls;
+ dnulls.resize(params.size(), false);
+ dvalues.reserve(params.size());
+
+ TString textNumberParam;
+ if (TypeId == INTERVALOID) {
+ i32 typmod = -1;
+ auto ok = NYql::ParsePgIntervalModifier(params[0], typmod);
+ if (!ok) {
+ TStringBuilder errMsg;
+ errMsg << "Error in 'typemodin' function: "
+ << NYql::NPg::LookupProc(TypeModInFuncId).Name
+ << ", reason: invalid parameter '" << params[0]
+ << "' for type pginterval";
+ return {-1, errMsg};
+ }
+ textNumberParam = Sprintf("%d", typmod);
+ dvalues.push_back(PointerGetDatum(textNumberParam.data()));
+ if (params.size() > 1) {
+ dvalues.push_back(PointerGetDatum(params[1].data()));
+ }
+ } else {
+ for (size_t i = 0; i < params.size(); ++i) {
+ dvalues.push_back(PointerGetDatum(params[i].data()));
+ }
+ }
+
+ NMiniKQL::TScopedAlloc alloc(__LOCATION__);
+ NMiniKQL::TPAllocScope scope;
+ ArrayType* paramsArray = nullptr;
+ Y_DEFER {
+ if (paramsArray) {
+ pfree(paramsArray);
+ }
+ };
+ PG_TRY();
+ {
+ int ndims = 0;
+ int dims[MAXDIM];
+ int lbs[MAXDIM];
+
+ ndims = 1;
+ dims[0] = params.size();
+ lbs[0] = 1;
+
+ const auto& cstringDesc = NYql::NPg::LookupType(CSTRINGOID);
+ paramsArray = construct_md_array(dvalues.data(), dnulls.data(), ndims, dims, lbs,
+ cstringDesc.TypeId,
+ cstringDesc.TypeLen,
+ cstringDesc.PassByValue,
+ cstringDesc.TypeAlign);
+
+ FmgrInfo finfo;
+ InitFunc(TypeModInFuncId, &finfo, 1, 1);
+ LOCAL_FCINFO(callInfo, 1);
+ Zero(*callInfo);
+ callInfo->flinfo = &finfo;
+ callInfo->nargs = 1;
+ callInfo->fncollation = DEFAULT_COLLATION_OID;
+ callInfo->isnull = false;
+ callInfo->args[0] = { PointerGetDatum(paramsArray), false };
+
+ auto result = finfo.fn_addr(callInfo);
+ Y_ENSURE(!callInfo->isnull);
+ return {DatumGetInt32(result), {}};
+ }
+ PG_CATCH();
+ {
+ auto error_data = CopyErrorData();
+ TStringBuilder errMsg;
+ errMsg << "Error in 'typemodin' function: "
+ << NYql::NPg::LookupProc(TypeModInFuncId).Name
+ << ", reason: " << error_data->message;
+ FreeErrorData(error_data);
+ FlushErrorState();
+ return {-1, errMsg};
+ }
+ PG_END_TRY();
+ }
+
+ TMaybe<TString> Validate(const TStringBuf binary) {
+ NMiniKQL::TScopedAlloc alloc(__LOCATION__);
+ NMiniKQL::TPAllocScope scope;
+ Datum datum = 0;
+ Y_DEFER {
+ if (!PassByValue && datum) {
+ pfree((void*)datum);
+ }
+ };
+ PG_TRY();
+ {
+ datum = Receive(binary.Data(), binary.Size());
+ return {};
+ }
+ PG_CATCH();
+ {
+ auto error_data = CopyErrorData();
+ TStringBuilder errMsg;
+ errMsg << "Error in 'recv' function: "
+ << NYql::NPg::LookupProc(ReceiveFuncId).Name
+ << ", reason: " << error_data->message;
+ FreeErrorData(error_data);
+ FlushErrorState();
+ return errMsg;
+ }
+ PG_END_TRY();
+ }
+
+ TCoerceResult Coerce(const TStringBuf binary, i32 typmod) {
+ NMiniKQL::TScopedAlloc alloc(__LOCATION__);
+ NMiniKQL::TPAllocScope scope;
+ Datum datum = 0;
+ Datum datumCasted = 0;
+ text* serialized = nullptr;
+ Y_DEFER {
+ if (!PassByValue) {
+ if (datum) {
+ pfree((void*)datum);
+ }
+ if (datumCasted && datumCasted != datum) {
+ pfree((void*)datumCasted);
+ }
+ }
+ if (serialized) {
+ pfree(serialized);
+ }
+ };
+ PG_TRY();
+ {
+ datum = Receive(binary.Data(), binary.Size());
+
+ const auto& cast = NYql::NPg::LookupCast(TypeId, TypeId);
+ FmgrInfo finfo;
+ InitFunc(cast.FunctionId, &finfo, 2, 3);
+ LOCAL_FCINFO(callInfo, 3);
+ Zero(*callInfo);
+ callInfo->flinfo = &finfo;
+ callInfo->nargs = 3;
+ callInfo->fncollation = DEFAULT_COLLATION_OID;
+ callInfo->isnull = false;
+ callInfo->args[0] = { datum, false };
+ callInfo->args[1] = { Int32GetDatum(typmod), false };
+ callInfo->args[2] = { BoolGetDatum(false), false };
+
+ datumCasted = finfo.fn_addr(callInfo);
+ Y_ENSURE(!callInfo->isnull);
+
+ if (datum == datumCasted) {
+ return {{}, {}};
+ } else {
+ FmgrInfo finfo;
+ InitFunc(SendFuncId, &finfo, 1, 1);
+ LOCAL_FCINFO(callInfo, 1);
+ Zero(*callInfo);
+ callInfo->flinfo = &finfo;
+ callInfo->nargs = 1;
+ callInfo->fncollation = DEFAULT_COLLATION_OID;
+ callInfo->isnull = false;
+ callInfo->args[0] = { datumCasted, false };
+
+ serialized = (text*)finfo.fn_addr(callInfo);
+ Y_ENSURE(!callInfo->isnull);
+ return {TString(NMiniKQL::GetVarBuf(serialized)), {}};
+ }
+ }
+ PG_CATCH();
+ {
+ auto error_data = CopyErrorData();
+ TStringBuilder errMsg;
+ errMsg << "Error in 'cast' function: "
+ << NYql::NPg::LookupProc(ReceiveFuncId).Name
+ << ", reason: " << error_data->message;
+ FreeErrorData(error_data);
+ FlushErrorState();
+ return {{}, errMsg};
+ }
+ PG_END_TRY();
+ }
+
private:
Datum Receive(const char* data, size_t size) const {
StringInfoData stringInfo;
@@ -3175,8 +3374,9 @@ private:
}
public:
- const TString YdbTypeName;
+ TString YdbTypeName;
ui32 StoredSize = 0; // size in local db, 0 for variable size
+ bool NeedsCoercion = false;
};
class TPgTypeDescriptors {
@@ -3230,17 +3430,33 @@ void* TypeDescFromPgTypeId(ui32 pgTypeId) {
return (void*)TPgTypeDescriptors::Instance().Find(pgTypeId);
}
-const char* PgTypeNameFromTypeDesc(void* typeDesc) {
+TString PgTypeNameFromTypeDesc(void* typeDesc, const TString& typeMod) {
if (!typeDesc) {
return "";
}
- return static_cast<TPgTypeDescriptor*>(typeDesc)->YdbTypeName.data();
+ auto* pgTypeDesc = static_cast<TPgTypeDescriptor*>(typeDesc);
+ if (typeMod.empty()) {
+ return pgTypeDesc->YdbTypeName;
+ }
+ return pgTypeDesc->YdbTypeName + INTERNAL_TYPE_AND_MOD_SEPARATOR + typeMod;
}
void* TypeDescFromPgTypeName(const TStringBuf name) {
+ auto space = name.find_first_of(INTERNAL_TYPE_AND_MOD_SEPARATOR);
+ if (space != TStringBuf::npos) {
+ return (void*)TPgTypeDescriptors::Instance().Find(name.substr(0, space));
+ }
return (void*)TPgTypeDescriptors::Instance().Find(name);
}
+TString TypeModFromPgTypeName(const TStringBuf name) {
+ auto space = name.find_first_of(INTERNAL_TYPE_AND_MOD_SEPARATOR);
+ if (space != TStringBuf::npos) {
+ return TString(name.substr(space + 1));
+ }
+ return {};
+}
+
bool TypeDescIsComparable(void* typeDesc) {
if (!typeDesc) {
return false;
@@ -3255,6 +3471,13 @@ ui32 TypeDescGetStoredSize(void* typeDesc) {
return static_cast<TPgTypeDescriptor*>(typeDesc)->StoredSize;
}
+bool TypeDescNeedsCoercion(void* typeDesc) {
+ if (!typeDesc) {
+ return false;
+ }
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->NeedsCoercion;
+}
+
int PgNativeBinaryCompare(const char* dataL, size_t sizeL, const char* dataR, size_t sizeR, void* typeDesc) {
return static_cast<TPgTypeDescriptor*>(typeDesc)->Compare(dataL, sizeL, dataR, sizeR);
}
@@ -3263,6 +3486,27 @@ ui64 PgNativeBinaryHash(const char* data, size_t size, void* typeDesc) {
return static_cast<TPgTypeDescriptor*>(typeDesc)->Hash(data, size);
}
+TTypeModResult BinaryTypeModFromTextTypeMod(const TString& str, void* typeDesc) {
+ if (!typeDesc) {
+ return {-1, "invalid type descriptor"};
+ }
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->ReadTypeMod(str);
+}
+
+TMaybe<TString> PgNativeBinaryValidate(const TStringBuf binary, void* typeDesc) {
+ if (!typeDesc) {
+ return "invalid type descriptor";
+ }
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->Validate(binary);
+}
+
+TCoerceResult PgNativeBinaryCoerce(const TStringBuf binary, void* typeDesc, i32 typmod) {
+ if (!typeDesc) {
+ return {{}, "invalid type descriptor"};
+ }
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->Coerce(binary, typmod);
+}
+
TConvertResult PgNativeBinaryFromNativeText(const TString& str, ui32 pgTypeId) {
auto* typeDesc = TypeDescFromPgTypeId(pgTypeId);
Y_VERIFY(typeDesc);
diff --git a/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h b/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h
index 831ffac1440..0a8fb161b88 100644
--- a/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h
+++ b/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h
@@ -1,25 +1,44 @@
#pragma once
#include <util/generic/strbuf.h>
+#include <util/generic/maybe.h>
namespace NKikimr::NPg {
ui32 PgTypeIdFromTypeDesc(void* typeDesc);
void* TypeDescFromPgTypeId(ui32 pgTypeId);
-const char* PgTypeNameFromTypeDesc(void* typeDesc);
+TString PgTypeNameFromTypeDesc(void* typeDesc, const TString& typeMod = {});
void* TypeDescFromPgTypeName(const TStringBuf name);
+TString TypeModFromPgTypeName(const TStringBuf name);
bool TypeDescIsComparable(void* typeDesc);
ui32 TypeDescGetStoredSize(void* typeDesc);
+bool TypeDescNeedsCoercion(void* typeDesc);
int PgNativeBinaryCompare(const char* dataL, size_t sizeL, const char* dataR, size_t sizeR, void* typeDesc);
ui64 PgNativeBinaryHash(const char* data, size_t size, void* typeDesc);
+struct TTypeModResult {
+ i32 Typmod = -1;
+ TMaybe<TString> Error;
+};
+
+TTypeModResult BinaryTypeModFromTextTypeMod(const TString& str, void* typeDesc);
+
+TMaybe<TString> PgNativeBinaryValidate(const TStringBuf binary, void* typeDesc);
+
+struct TCoerceResult {
+ TMaybe<TString> NewValue;
+ TMaybe<TString> Error;
+};
+
+TCoerceResult PgNativeBinaryCoerce(const TStringBuf binary, void* typeDesc, i32 typmod);
+
struct TConvertResult {
TString Str;
- TString Error;
+ TMaybe<TString> Error;
};
TConvertResult PgNativeBinaryFromNativeText(const TString& str, ui32 pgTypeId);
diff --git a/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp b/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp
index ac9404e30d9..0366da57efc 100644
--- a/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp
+++ b/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp
@@ -285,8 +285,9 @@ void* TypeDescFromPgTypeId(ui32 pgTypeId) {
return {};
}
-const char* PgTypeNameFromTypeDesc(void* typeDesc) {
+TString PgTypeNameFromTypeDesc(void* typeDesc, const TString& typeMod) {
Y_UNUSED(typeDesc);
+ Y_UNUSED(typeMod);
return "";
}
@@ -295,6 +296,11 @@ void* TypeDescFromPgTypeName(const TStringBuf name) {
return {};
}
+TString TypeModFromPgTypeName(const TStringBuf name) {
+ Y_UNUSED(name);
+ return {};
+}
+
bool TypeDescIsComparable(void* typeDesc) {
Y_UNUSED(typeDesc);
throw yexception() << "PG types are not supported";
@@ -305,6 +311,11 @@ ui32 TypeDescGetStoredSize(void* typeDesc) {
throw yexception() << "PG types are not supported";
}
+bool TypeDescNeedsCoercion(void* typeDesc) {
+ Y_UNUSED(typeDesc);
+ throw yexception() << "PG types are not supported";
+}
+
int PgNativeBinaryCompare(const char* dataL, size_t sizeL, const char* dataR, size_t sizeR, void* typeDesc) {
Y_UNUSED(dataL);
Y_UNUSED(sizeL);
@@ -321,6 +332,25 @@ ui64 PgNativeBinaryHash(const char* data, size_t size, void* typeDesc) {
throw yexception() << "PG types are not supported";
}
+TTypeModResult BinaryTypeModFromTextTypeMod(const TString& str, void* typeDesc) {
+ Y_UNUSED(str);
+ Y_UNUSED(typeDesc);
+ throw yexception() << "PG types are not supported";
+}
+
+TMaybe<TString> PgNativeBinaryValidate(const TStringBuf binary, void* typeDesc) {
+ Y_UNUSED(binary);
+ Y_UNUSED(typeDesc);
+ throw yexception() << "PG types are not supported";
+}
+
+TCoerceResult PgNativeBinaryCoerce(const TStringBuf binary, void* typeDesc, i32 typmod) {
+ Y_UNUSED(binary);
+ Y_UNUSED(typeDesc);
+ Y_UNUSED(typmod);
+ throw yexception() << "PG types are not supported";
+}
+
TConvertResult PgNativeBinaryFromNativeText(const TString& str, ui32 pgTypeId) {
Y_UNUSED(str);
Y_UNUSED(pgTypeId);
diff --git a/ydb/public/api/protos/ydb_value.proto b/ydb/public/api/protos/ydb_value.proto
index bbee9e5c035..4093a50a271 100644
--- a/ydb/public/api/protos/ydb_value.proto
+++ b/ydb/public/api/protos/ydb_value.proto
@@ -51,12 +51,15 @@ message TaggedType {
}
message PgType {
+ string type_name = 10;
+ string type_modifier = 11;
+
// pg object id of the type
// full registry could be found here: https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
- uint32 oid = 1; // required
+ uint32 oid = 1;
// advanced type details useful for pg wire format proxying
- int32 typlen = 2; // optional, set to 0 by default
- int32 typmod = 3; // optional, set to 0 by default
+ int32 typlen = 2;
+ int32 typmod = 3;
}
message Type {
diff --git a/ydb/public/lib/json_value/ydb_json_value.cpp b/ydb/public/lib/json_value/ydb_json_value.cpp
index 50f2ea3f5b3..083127b89b3 100644
--- a/ydb/public/lib/json_value/ydb_json_value.cpp
+++ b/ydb/public/lib/json_value/ydb_json_value.cpp
@@ -658,7 +658,7 @@ namespace {
break;
case TTypeParser::ETypeKind::Pg: {
- TPgType pgType(0, -1, -1);
+ TPgType pgType(""); // TODO: correct type?
if (jsonValue.GetType() == NJson::JSON_STRING) {
ValueBuilder.Pg(TPgValue(TPgValue::VK_TEXT, jsonValue.GetString(), pgType));
} else if (jsonValue.GetType() == NJson::JSON_NULL) {
diff --git a/ydb/public/lib/json_value/ydb_json_value_ut.cpp b/ydb/public/lib/json_value/ydb_json_value_ut.cpp
index 0856192673d..365e821fa3a 100644
--- a/ydb/public/lib/json_value/ydb_json_value_ut.cpp
+++ b/ydb/public/lib/json_value/ydb_json_value_ut.cpp
@@ -576,7 +576,7 @@ Y_UNIT_TEST_SUITE(JsonValueTest) {
}
Y_UNIT_TEST(PgValue) {
- TPgType pgType(1, 2, 3);
+ TPgType pgType("");
TPgValue v1(TPgValue::VK_TEXT, "text_value", pgType);
TPgValue v2(TPgValue::VK_BINARY, "binary_value", pgType);
TPgValue v3(TPgValue::VK_TEXT, "", pgType);
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/value_helpers/helpers.cpp b/ydb/public/sdk/cpp/client/impl/ydb_internal/value_helpers/helpers.cpp
index d2eff31232e..637dfde518a 100644
--- a/ydb/public/sdk/cpp/client/impl/ydb_internal/value_helpers/helpers.cpp
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/value_helpers/helpers.cpp
@@ -17,9 +17,8 @@ bool TypesEqual(const Ydb::Type& t1, const Ydb::Type& t2) {
return t1.decimal_type().precision() == t2.decimal_type().precision()
&& t1.decimal_type().scale() == t2.decimal_type().scale();
case Ydb::Type::kPgType:
- return t1.pg_type().oid() == t2.pg_type().oid()
- && t1.pg_type().typlen() == t2.pg_type().typlen()
- && t1.pg_type().typmod() == t2.pg_type().typmod();
+ return t1.pg_type().type_name() == t2.pg_type().type_name()
+ && t1.pg_type().type_modifier() == t2.pg_type().type_modifier();
case Ydb::Type::kOptionalType:
return TypesEqual(t1.optional_type().item(), t2.optional_type().item());
case Ydb::Type::kTaggedType:
diff --git a/ydb/public/sdk/cpp/client/ydb_value/value.cpp b/ydb/public/sdk/cpp/client/ydb_value/value.cpp
index 71c69959c69..1bb65d5e322 100644
--- a/ydb/public/sdk/cpp/client/ydb_value/value.cpp
+++ b/ydb/public/sdk/cpp/client/ydb_value/value.cpp
@@ -140,7 +140,11 @@ public:
TPgType GetPg() const {
CheckKind(ETypeKind::Pg, "GetPg");
const auto& pg = GetProto().pg_type();
- return TPgType(pg.oid(), pg.typlen(), pg.typmod());
+ TPgType type(pg.type_name(), pg.type_modifier());
+ type.Oid = pg.oid();
+ type.Typlen = pg.typlen();
+ type.Typmod = pg.typmod();
+ return type;
}
template<ETypeKind kind>
@@ -472,7 +476,8 @@ void FormatTypeInternal(TTypeParser& parser, IOutputStream& out) {
case TTypeParser::ETypeKind::Pg: {
auto pg = parser.GetPg();
- out << "Pg("sv << pg.Oid << ',' << pg.Typlen << ',' << pg.Typmod << ')';
+ out << "Pg('"sv << pg.TypeName << "\',\'" << pg.TypeModifier << "\',"
+ << pg.Oid << "," << pg.Typlen << ',' << pg.Typmod << ')';
break;
}
@@ -603,9 +608,8 @@ public:
void Pg(const TPgType& pgType) {
auto& pg = *GetProto().mutable_pg_type();
- pg.set_oid(pgType.Oid);
- pg.set_typlen(pgType.Typlen);
- pg.set_typmod(pgType.Typmod);
+ pg.set_type_name(pgType.TypeName);
+ pg.set_type_modifier(pgType.TypeModifier);
}
void BeginOptional() {
diff --git a/ydb/public/sdk/cpp/client/ydb_value/value.h b/ydb/public/sdk/cpp/client/ydb_value/value.h
index 5c7c885daa7..43d516afb9a 100644
--- a/ydb/public/sdk/cpp/client/ydb_value/value.h
+++ b/ydb/public/sdk/cpp/client/ydb_value/value.h
@@ -70,14 +70,16 @@ struct TDecimalType {
};
struct TPgType {
- ui32 Oid;
- i32 Typlen;
- i32 Typmod;
-
- TPgType(ui32 oid, i32 typlen, i32 typmod)
- : Oid(oid)
- , Typlen(typlen)
- , Typmod(typmod)
+ TString TypeName;
+ TString TypeModifier;
+
+ ui32 Oid = 0;
+ i32 Typlen = 0;
+ i32 Typmod = 0;
+
+ TPgType(const TString& typeName, const TString& typeModifier = {})
+ : TypeName(typeName)
+ , TypeModifier(typeModifier)
{}
};
diff --git a/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp b/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp
index 78f6ca72a2f..9a75fa76350 100644
--- a/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp
+++ b/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp
@@ -142,7 +142,7 @@ Y_UNIT_TEST_SUITE(YdbValue) {
.AddElement()
.Decimal(TDecimalType(8, 13))
.AddElement()
- .Pg(TPgType(1, 2, -3))
+ .Pg(TPgType("pgint2"))
.AddElement()
.BeginOptional()
.Primitive(EPrimitiveType::Utf8)
@@ -153,7 +153,7 @@ Y_UNIT_TEST_SUITE(YdbValue) {
.Build();
UNIT_ASSERT_NO_DIFF(FormatType(type),
- R"(Struct<'Member1':List<Uint32?>,'Member2':Dict<Int64,Tuple<Decimal(8,13),Pg(1,2,-3),Utf8?>>>)");
+ R"(Struct<'Member1':List<Uint32?>,'Member2':Dict<Int64,Tuple<Decimal(8,13),Pg('pgint2','',0,0,0),Utf8?>>>)");
}
Y_UNIT_TEST(BuildTypeReuse) {