22
33#include < ydb/library/yql/core/expr_nodes/yql_expr_nodes.h>
44#include < ydb/library/yql/core/yql_opt_utils.h>
5+ #include < ydb/library/yql/providers/s3/common/util.h>
56#include < ydb/library/yql/providers/s3/expr_nodes/yql_s3_expr_nodes.h>
67
78#include < ydb/library/yql/providers/common/provider/yql_provider.h>
@@ -26,6 +27,7 @@ TExprNode::TListType GetPartitionKeys(const TExprNode::TPtr& partBy) {
2627
2728 return {};
2829}
30+
2931}
3032
3133namespace {
@@ -64,7 +66,47 @@ class TS3DataSinkTypeAnnotationTransformer : public TVisitorTransformerBase {
6466 return TStatus::Error;
6567 }
6668
67- auto source = input->Child (TS3WriteObject::idx_Input);
69+ const auto targetNode = input->Child (TS3WriteObject::idx_Target);
70+ if (!TS3Target::Match (targetNode)) {
71+ ctx.AddError (TIssue (ctx.GetPosition (targetNode->Pos ()), " Expected S3 target." ));
72+ return TStatus::Error;
73+ }
74+
75+ const TTypeAnnotationNode* targetType = nullptr ;
76+ if (const TS3Target target (targetNode); const auto settings = target.Settings ()) {
77+ if (const auto userschema = GetSetting (settings.Cast ().Ref (), " userschema" )) {
78+ targetType = userschema->Child (1 )->GetTypeAnn ()->Cast <TTypeExprType>()->GetType ();
79+ }
80+ }
81+
82+ const auto source = input->ChildPtr (TS3WriteObject::idx_Input);
83+ if (const auto maybeTuple = TMaybeNode<TExprList>(source)) {
84+ const auto tuple = maybeTuple.Cast ();
85+
86+ TVector<TExprBase> convertedValues;
87+ convertedValues.reserve (tuple.Size ());
88+ for (const auto & value : tuple) {
89+ if (!EnsureStructType (input->Pos (), *value.Ref ().GetTypeAnn (), ctx)) {
90+ return TStatus::Error;
91+ }
92+
93+ TExprNode::TPtr node = value.Ptr ();
94+ if (targetType && TryConvertTo (node, *targetType, ctx) == TStatus::Error) {
95+ ctx.AddError (TIssue (ctx.GetPosition (source->Pos ()), " Failed to convert input columns types to scheme types" ));
96+ return TStatus::Error;
97+ }
98+
99+ convertedValues.emplace_back (std::move (node));
100+ }
101+
102+ const auto list = Build<TCoAsList>(ctx, input->Pos ())
103+ .Add (std::move (convertedValues))
104+ .Done ();
105+
106+ input->ChildRef (TS3WriteObject::idx_Input) = list.Ptr ();
107+ return TStatus::Repeat;
108+ }
109+
68110 if (!EnsureListType (*source, ctx)) {
69111 return TStatus::Error;
70112 }
@@ -74,23 +116,17 @@ class TS3DataSinkTypeAnnotationTransformer : public TVisitorTransformerBase {
74116 return TStatus::Error;
75117 }
76118
77- auto target = input->Child (TS3WriteObject::idx_Target);
78- if (!TS3Target::Match (target)) {
79- ctx.AddError (TIssue (ctx.GetPosition (target->Pos ()), " Expected S3 target." ));
119+ if (!NS3Util::ValidateS3ReadWriteSchema (sourceType->Cast <TStructExprType>(), ctx)) {
80120 return TStatus::Error;
81121 }
82122
83- TS3Target tgt (target);
84- if (auto settings = tgt.Settings ()) {
85- if (auto userschema = GetSetting (settings.Cast ().Ref (), " userschema" )) {
86- const TTypeAnnotationNode* targetType = userschema->Child (1 )->GetTypeAnn ()->Cast <TTypeExprType>()->GetType ();
87- if (!IsSameAnnotation (*targetType, *sourceType)) {
88- ctx.AddError (TIssue (ctx.GetPosition (source->Pos ()),
89- TStringBuilder () << " Type mismatch between schema type: " << *targetType
90- << " and actual data type: " << *sourceType << " , diff is: "
91- << GetTypeDiff (*targetType, *sourceType)));
92- return TStatus::Error;
93- }
123+ if (targetType) {
124+ const auto status = TryConvertTo (input->ChildRef (TS3WriteObject::idx_Input), *ctx.MakeType <TListExprType>(targetType), ctx);
125+ if (status == TStatus::Error) {
126+ ctx.AddError (TIssue (ctx.GetPosition (source->Pos ()), " Row type mismatch for S3 external table" ));
127+ return TStatus::Error;
128+ } else if (status != TStatus::Ok) {
129+ return status;
94130 }
95131 }
96132
0 commit comments