22#include " actors/kqp_ic_gateway_actors.h"
33
44#include < ydb/core/base/path.h>
5+ #include < ydb/core/external_sources/external_source_factory.h>
56#include < ydb/core/kqp/federated_query/kqp_federated_query_actors.h>
67#include < ydb/core/kqp/gateway/utils/scheme_helpers.h>
78#include < ydb/core/statistics/events.h>
89#include < ydb/core/statistics/stat_service.h>
910
1011#include < ydb/library/actors/core/hfunc.h>
1112#include < ydb/library/actors/core/log.h>
13+ #include < ydb/library/yql/utils/signals/utils.h>
1214
1315
1416namespace NKikimr ::NKqp {
@@ -63,7 +65,7 @@ NavigateEntryResult CreateNavigateEntry(const std::pair<TIndexId, TString>& pair
6365 entry.Operation = NSchemeCache::TSchemeCacheNavigate::EOp::OpList;
6466 entry.SyncVersion = true ;
6567 entry.ShowPrivatePath = settings.WithPrivateTables_ ;
66- return {entry, pair.second , std::nullopt };
68+ return {std::move ( entry) , pair.second , std::nullopt };
6769}
6870
6971std::optional<NavigateEntryResult> CreateNavigateExternalEntry (const TString& path, bool externalDataSource) {
@@ -279,6 +281,7 @@ TTableMetadataResult GetExternalDataSourceMetadataResult(const NSchemeCache::TSc
279281 tableMeta->ExternalSource .DataSourceAuth = description.GetAuth ();
280282 tableMeta->ExternalSource .Properties = description.GetProperties ();
281283 tableMeta->ExternalSource .DataSourcePath = tableName;
284+ tableMeta->ExternalSource .TableLocation = JoinPath (entry.Path );
282285 return result;
283286}
284287
@@ -470,6 +473,61 @@ NThreading::TFuture<TEvDescribeSecretsResponse::TDescription> LoadExternalDataSo
470473 return DescribeExternalDataSourceSecrets (authDescription, userToken ? userToken->GetUserSID () : " " , actorSystem, maximalSecretsSnapshotWaitTime);
471474}
472475
476+ NExternalSource::TAuth MakeAuth (const NYql::TExternalSource& metadata) {
477+ switch (metadata.DataSourceAuth .identity_case ()) {
478+ case NKikimrSchemeOp::TAuth::kNone :
479+ return NExternalSource::NAuth::MakeNone ();
480+ case NKikimrSchemeOp::TAuth::kServiceAccount :
481+ return NExternalSource::NAuth::MakeServiceAccount (metadata.DataSourceAuth .GetServiceAccount ().GetId (), metadata.ServiceAccountIdSignature );
482+ case NKikimrSchemeOp::TAuth::kAws :
483+ return NExternalSource::NAuth::MakeAws (metadata.AwsAccessKeyId , metadata.AwsSecretAccessKey , metadata.DataSourceAuth .GetAws ().GetAwsRegion ());
484+ case NKikimrSchemeOp::TAuth::kBasic :
485+ case NKikimrSchemeOp::TAuth::kMdbBasic :
486+ case NKikimrSchemeOp::TAuth::kToken :
487+ case NKikimrSchemeOp::TAuth::IDENTITY_NOT_SET:
488+ Y_ABORT (" Unimplemented external source auth: %d" , metadata.DataSourceAuth .identity_case ());
489+ break ;
490+ }
491+ Y_UNREACHABLE ();
492+ }
493+
494+ std::shared_ptr<NExternalSource::TMetadata> ConvertToExternalSourceMetadata (const NYql::TKikimrTableMetadata& tableMetadata) {
495+ auto metadata = std::make_shared<NExternalSource::TMetadata>();
496+ metadata->TableLocation = tableMetadata.ExternalSource .TableLocation ;
497+ metadata->DataSourceLocation = tableMetadata.ExternalSource .DataSourceLocation ;
498+ metadata->DataSourcePath = tableMetadata.ExternalSource .DataSourcePath ;
499+ metadata->Attributes = tableMetadata.Attributes ;
500+ metadata->Auth = MakeAuth (tableMetadata.ExternalSource );
501+ return metadata;
502+ }
503+
504+ // dynamic metadata from IExternalSource here is propagated into TKikimrTableMetadata, which will be returned as a result of LoadTableMetadata()
505+ bool EnrichMetadata (NYql::TKikimrTableMetadata& tableMetadata, const NExternalSource::TMetadata& dynamicMetadata) {
506+ ui32 id = 0 ;
507+ for (const auto & column : dynamicMetadata.Schema .column ()) {
508+ Ydb::Type::PrimitiveTypeId typeId {};
509+ if (column.type ().has_type_id ()) {
510+ typeId = column.type ().type_id ();
511+ } else if (column.type ().has_optional_type ()) {
512+ typeId = column.type ().optional_type ().item ().type_id ();
513+ } else {
514+ Y_ABORT_UNLESS (false );
515+ }
516+ const auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType (typeId, nullptr );
517+ auto typeName = GetTypeName (typeInfoMod);
518+
519+ tableMetadata.Columns .emplace (
520+ column.name (),
521+ NYql::TKikimrColumnMetadata (
522+ column.name (), id, typeName, !column.type ().has_optional_type (), typeInfoMod.TypeInfo , typeInfoMod.TypeMod
523+ )
524+ );
525+ ++id;
526+ }
527+ tableMetadata.Attributes = dynamicMetadata.Attributes ;
528+ return true ;
529+ }
530+
473531} // anonymous namespace
474532
475533
@@ -680,9 +738,11 @@ NThreading::TFuture<TTableMetadataResult> TKqpTableMetadataLoader::LoadTableMeta
680738 // In this syntax, information about path_in_external_system is already known and we only need information about external_data_source.
681739 // To do this, we go to the DefaultCluster and get information about external_data_source from scheme shard
682740 const bool resolveEntityInsideDataSource = (cluster != Cluster);
741+ TMaybe<TString> externalPath;
683742 TPath entityName = id;
684743 if constexpr (std::is_same_v<TPath, TString>) {
685744 if (resolveEntityInsideDataSource) {
745+ externalPath = entityName;
686746 entityName = cluster;
687747 }
688748 } else {
@@ -720,7 +780,7 @@ NThreading::TFuture<TTableMetadataResult> TKqpTableMetadataLoader::LoadTableMeta
720780 ActorSystem,
721781 schemeCacheId,
722782 ev.Release (),
723- [userToken, database, cluster, mainCluster = Cluster, table, settings, expectedSchemaVersion, this , queryName]
783+ [userToken, database, cluster, mainCluster = Cluster, table, settings, expectedSchemaVersion, this , queryName, externalPath ]
724784 (TPromise<TResult> promise, TResponse&& response) mutable
725785 {
726786 try {
@@ -759,16 +819,41 @@ NThreading::TFuture<TTableMetadataResult> TKqpTableMetadataLoader::LoadTableMeta
759819
760820 switch (entry.Kind ) {
761821 case EKind::KindExternalDataSource: {
822+ if (externalPath) {
823+ entry.Path = SplitPath (*externalPath);
824+ }
762825 auto externalDataSourceMetadata = GetLoadTableMetadataResult (entry, cluster, mainCluster, table);
763826 if (!externalDataSourceMetadata.Success () || !settings.RequestAuthInfo_ ) {
764827 promise.SetValue (externalDataSourceMetadata);
765828 return ;
766829 }
767830 LoadExternalDataSourceSecretValues (entry, userToken, MaximalSecretsSnapshotWaitTime, ActorSystem)
768- .Subscribe ([promise, externalDataSourceMetadata](const TFuture<TEvDescribeSecretsResponse::TDescription>& result) mutable
831+ .Subscribe ([promise, externalDataSourceMetadata, settings ](const TFuture<TEvDescribeSecretsResponse::TDescription>& result) mutable
769832 {
770833 UpdateExternalDataSourceSecretsValue (externalDataSourceMetadata, result.GetValue ());
771- promise.SetValue (externalDataSourceMetadata);
834+ NExternalSource::IExternalSource::TPtr externalSource;
835+ if (settings.ExternalSourceFactory ) {
836+ externalSource = settings.ExternalSourceFactory ->GetOrCreate (externalDataSourceMetadata.Metadata ->ExternalSource .Type );
837+ }
838+
839+ if (externalSource && externalSource->CanLoadDynamicMetadata ()) {
840+ auto externalSourceMeta = ConvertToExternalSourceMetadata (*externalDataSourceMetadata.Metadata );
841+ externalSourceMeta->Attributes = settings.ReadAttributes ; // attributes, collected from AST
842+ externalSource->LoadDynamicMetadata (std::move (externalSourceMeta))
843+ .Subscribe ([promise = std::move (promise), externalDataSourceMetadata](const TFuture<std::shared_ptr<NExternalSource::TMetadata>>& result) mutable {
844+ TTableMetadataResult wrapper;
845+ if (result.HasValue () && (!result.GetValue ()->Changed || EnrichMetadata (*externalDataSourceMetadata.Metadata , *result.GetValue ()))) {
846+ wrapper.SetSuccess ();
847+ wrapper.Metadata = externalDataSourceMetadata.Metadata ;
848+ } else {
849+ // TODO: forward exception from result
850+ wrapper.SetException (yexception () << " LoadDynamicMetadata failed" );
851+ }
852+ promise.SetValue (wrapper);
853+ });
854+ } else {
855+ promise.SetValue (externalDataSourceMetadata);
856+ }
772857 });
773858 break ;
774859 }
@@ -785,7 +870,8 @@ NThreading::TFuture<TTableMetadataResult> TKqpTableMetadataLoader::LoadTableMeta
785870 .Apply ([promise, externalTableMetadata](const TFuture<TTableMetadataResult>& result) mutable
786871 {
787872 auto externalDataSourceMetadata = result.GetValue ();
788- promise.SetValue (EnrichExternalTable (externalTableMetadata, externalDataSourceMetadata));
873+ auto newMetadata = EnrichExternalTable (externalTableMetadata, externalDataSourceMetadata);
874+ promise.SetValue (std::move (newMetadata));
789875 });
790876 break ;
791877 }
0 commit comments