From 284019aa1d85b21ceadbd6f2e7f13243384066dc Mon Sep 17 00:00:00 2001 From: Vitaly Stoyan Date: Thu, 29 Feb 2024 14:15:49 +0000 Subject: [PATCH] init --- .../yql/core/type_ann/type_ann_core.cpp | 1 + ydb/library/yql/core/type_ann/type_ann_pg.cpp | 167 +++++++++++++++++- ydb/library/yql/core/type_ann/type_ann_pg.h | 1 + .../yql/minikql/mkql_program_builder.cpp | 26 +++ .../yql/minikql/mkql_program_builder.h | 1 + .../yql/minikql/mkql_runtime_version.h | 2 +- .../yql/parser/pg_wrapper/comp_factory.cpp | 132 ++++++++++++++ .../common/mkql/yql_provider_mkql.cpp | 12 +- .../sql/dq_file/part9/canondata/result.json | 22 +++ .../hybrid_file/part7/canondata/result.json | 14 ++ .../tests/sql/sql2yql/canondata/result.json | 7 + .../sql/suites/pg/record_from_table_row.sql | 4 + .../part9/canondata/result.json | 21 +++ 13 files changed, 404 insertions(+), 6 deletions(-) create mode 100644 ydb/library/yql/tests/sql/suites/pg/record_from_table_row.sql diff --git a/ydb/library/yql/core/type_ann/type_ann_core.cpp b/ydb/library/yql/core/type_ann/type_ann_core.cpp index ca13ccec7305..b55084b99742 100644 --- a/ydb/library/yql/core/type_ann/type_ann_core.cpp +++ b/ydb/library/yql/core/type_ann/type_ann_core.cpp @@ -12086,6 +12086,7 @@ template Functions["PgGroupRef"] = &PgGroupRefWrapper; Functions["PgGrouping"] = &PgGroupingWrapper; Functions["PgGroupingSet"] = &PgGroupingSetWrapper; + Functions["PgToRecord"] = &PgToRecordWrapper; Functions["AutoDemux"] = &AutoDemuxWrapper; Functions["AggrCountInit"] = &AggrCountInitWrapper; diff --git a/ydb/library/yql/core/type_ann/type_ann_pg.cpp b/ydb/library/yql/core/type_ann/type_ann_pg.cpp index bbba4d615976..46a5c47385eb 100644 --- a/ydb/library/yql/core/type_ann/type_ann_pg.cpp +++ b/ydb/library/yql/core/type_ann/type_ann_pg.cpp @@ -1583,6 +1583,10 @@ bool ScanColumns(TExprNode::TPtr root, TInputs& inputs, const THashSet& } TString foundAlias; + bool matchedAlias = false; + ui32 matchedAliasI = 0; + TMaybe matchedAliasIndex; + TMaybe matchedAliasIndexI; for (ui32 priority : {TInput::Projection, TInput::Current, TInput::External}) { ui32 matches = 0; for (ui32 inputIndex = 0; inputIndex < inputs.size(); ++inputIndex) { @@ -1597,6 +1601,16 @@ bool ScanColumns(TExprNode::TPtr root, TInputs& inputs, const THashSet& } } + if (!x.Alias.empty()) { + if (node->Tail().Content() == x.Alias) { + matchedAlias = true; + matchedAliasIndex = inputIndex; + } else if (AsciiEqualsIgnoreCase(node->Tail().Content(), x.Alias)) { + ++matchedAliasI; + matchedAliasIndexI = inputIndex; + } + } + auto pos = x.Type->FindItemI(node->Tail().Content()); if (pos) { foundAlias = x.Alias; @@ -1624,10 +1638,39 @@ bool ScanColumns(TExprNode::TPtr root, TInputs& inputs, const THashSet& return true; } - ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(node->Pos()), - TStringBuilder() << "No such column: " << node->Tail().Content())); - isError = true; - return false; + TInput* tableRefInput = nullptr; + if (matchedAlias) { + tableRefInput = &inputs[*matchedAliasIndex]; + } else { + if (matchedAliasI > 1) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(node->Pos()), + TStringBuilder() << "Table reference is ambiguous: " << node->Tail().Content())); + isError = true; + return false; + } + + if (matchedAliasI == 1) { + tableRefInput = &inputs[*matchedAliasIndexI]; + } + } + + if (!tableRefInput) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(node->Pos()), + TStringBuilder() << "No such column: " << node->Tail().Content())); + isError = true; + return false; + } + + for (const auto& item : tableRefInput->Type->GetItems()) { + if (!item->GetName().StartsWith("_yql_")) { + refs.insert(TString(item->GetName())); + if (tableRefInput->Priority == TInput::External) { + tableRefInput->UsedExternalColumns.insert(TString(item->GetName())); + } + } + } + + return true; } } @@ -1890,6 +1933,8 @@ IGraphTransformer::TStatus RebuildLambdaColumns(const TExprNode::TPtr& root, con } if (node->IsCallable("PgColumnRef")) { + const TInput* matchedAliasInput = nullptr; + const TInput* matchedAliasInputI = nullptr; for (ui32 priority : { TInput::Projection, TInput::Current, TInput::External }) { for (const auto& x : inputs) { if (priority != x.Priority) { @@ -1902,6 +1947,14 @@ IGraphTransformer::TStatus RebuildLambdaColumns(const TExprNode::TPtr& root, con } } + if (!x.Alias.empty()) { + if (node->Tail().Content() == x.Alias) { + matchedAliasInput = &x; + } else if (AsciiEqualsIgnoreCase(node->Tail().Content(), x.Alias)) { + matchedAliasInputI = &x; + } + } + auto pos = x.Type->FindItemI(node->Tail().Content()); if (pos) { return ctx.Expr.Builder(node->Pos()) @@ -1914,6 +1967,41 @@ IGraphTransformer::TStatus RebuildLambdaColumns(const TExprNode::TPtr& root, con } } + if (!matchedAliasInput && matchedAliasInputI) { + matchedAliasInput = matchedAliasInputI; + } + + if (matchedAliasInput) { + return ctx.Expr.Builder(node->Pos()) + .Callable("PgToRecord") + .Callable(0, "DivePrefixMembers") + .Add(0, argNode) + .List(1) + .Atom(0, MakeAliasedColumn(matchedAliasInput->Alias, "")) + .Seal() + .Seal() + .List(1) + .Do([&](TExprNodeBuilder& parent) -> TExprNodeBuilder & { + ui32 pos = 0; + for (ui32 i = 0; i < matchedAliasInput->Type->GetSize(); ++i) { + auto columnName = matchedAliasInput->Order ? + matchedAliasInput->Order.GetRef()[i] : + matchedAliasInput->Type->GetItems()[i]->GetName(); + if (!columnName.StartsWith("_yql_")) { + parent.List(pos++) + .Atom(0, columnName) + .Atom(1, columnName) + .Seal(); + } + } + + return parent; + }) + .Seal() + .Seal() + .Build(); + } + YQL_ENSURE(false, "Missing input"); } @@ -5276,5 +5364,76 @@ IGraphTransformer::TStatus PgGroupingSetWrapper(const TExprNode::TPtr& input, TE return IGraphTransformer::TStatus::Ok; } +IGraphTransformer::TStatus PgToRecordWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) { + if (!EnsureArgsCount(*input, 2, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + if (!EnsureStructType(input->Head(), ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + auto structType = input->Head().GetTypeAnn()->Cast(); + bool hasConversions = false; + for (ui32 pass = 0; pass < 2; ++pass) { + TExprNode::TListType convItems; + for (ui32 i = 0; i < structType->GetSize(); ++i) { + ui32 pgType; + bool convertToPg; + if (!ExtractPgType(structType->GetItems()[i]->GetItemType(), pgType, convertToPg, input->Head().Pos(), ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + hasConversions = hasConversions || convertToPg; + if (pass == 1) { + auto name = ctx.Expr.NewAtom(input->Head().Pos(), structType->GetItems()[i]->GetName()); + auto member = ctx.Expr.NewCallable(input->Head().Pos(), "Member", { input->HeadPtr(), name} ); + if (convertToPg) { + member = ctx.Expr.NewCallable(input->Head().Pos(), "ToPg", { member }); + } + + convItems.push_back(ctx.Expr.NewList(input->Head().Pos(), { name, member })); + } + } + + if (!hasConversions) { + break; + } + + if (pass == 1) { + output = ctx.Expr.ChangeChild(*input, 0, ctx.Expr.NewCallable(input->Head().Pos(), "AsStruct", std::move(convItems))); + return IGraphTransformer::TStatus::Repeat; + } + } + + if (!EnsureTuple(input->Tail(), ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + for (const auto& child : input->Tail().Children()) { + if (!EnsureTupleSize(*child, 2, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + if (!EnsureAtom(child->Head(), ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + if (!EnsureAtom(child->Tail(), ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + auto pos = structType->FindItem(child->Tail().Content()); + if (!pos) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(child->Pos()), + TStringBuilder() << "Missing member: " << child->Tail().Content())); + return IGraphTransformer::TStatus::Error; + } + } + + input->SetTypeAnn(ctx.Expr.MakeType(NPg::LookupType("record").TypeId)); + return IGraphTransformer::TStatus::Ok; +} + } // namespace NTypeAnnImpl } diff --git a/ydb/library/yql/core/type_ann/type_ann_pg.h b/ydb/library/yql/core/type_ann/type_ann_pg.h index d8608fd7122f..afbcdc503715 100644 --- a/ydb/library/yql/core/type_ann/type_ann_pg.h +++ b/ydb/library/yql/core/type_ann/type_ann_pg.h @@ -53,6 +53,7 @@ IGraphTransformer::TStatus PgSubLinkWrapper(const TExprNode::TPtr& input, TExprN IGraphTransformer::TStatus PgGroupRefWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus PgGroupingWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus PgGroupingSetWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); +IGraphTransformer::TStatus PgToRecordWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); } // namespace NTypeAnnImpl } // namespace NYql diff --git a/ydb/library/yql/minikql/mkql_program_builder.cpp b/ydb/library/yql/minikql/mkql_program_builder.cpp index a210c92921a5..62b74ce80e2e 100644 --- a/ydb/library/yql/minikql/mkql_program_builder.cpp +++ b/ydb/library/yql/minikql/mkql_program_builder.cpp @@ -9,6 +9,7 @@ #include "ydb/library/yql/minikql/mkql_type_builder.h" #include "ydb/library/yql/core/sql_types/match_recognize.h" #include "ydb/library/yql/core/sql_types/time_order_recover.h" +#include #include #include @@ -5470,6 +5471,31 @@ TRuntimeNode TProgramBuilder::PgTableContent( return TRuntimeNode(callableBuilder.Build(), false); } +TRuntimeNode TProgramBuilder::PgToRecord(TRuntimeNode input, const TArrayRef>& members) { + if constexpr (RuntimeVersion < 48U) { + THROW yexception() << "Runtime version (" << RuntimeVersion << ") too old for " << __func__; + } + + MKQL_ENSURE(input.GetStaticType()->IsStruct(), "Expected struct"); + auto structType = AS_TYPE(TStructType, input.GetStaticType()); + for (ui32 i = 0; i < structType->GetMembersCount(); ++i) { + auto itemType = structType->GetMemberType(i); + MKQL_ENSURE(itemType->IsNull() || itemType->IsPg(), "Expected null or pg"); + } + + auto returnType = NewPgType(NYql::NPg::LookupType("record").TypeId); + TCallableBuilder callableBuilder(Env, __func__, returnType); + callableBuilder.Add(input); + TVector names; + for (const auto& x : members) { + names.push_back(NewDataLiteral(x.first)); + names.push_back(NewDataLiteral(x.second)); + } + + callableBuilder.Add(NewTuple(names)); + return TRuntimeNode(callableBuilder.Build(), false); +} + TRuntimeNode TProgramBuilder::PgCast(TRuntimeNode input, TType* returnType, TRuntimeNode typeMod) { if constexpr (RuntimeVersion < 30U) { THROW yexception() << "Runtime version (" << RuntimeVersion << ") too old for " << __func__; diff --git a/ydb/library/yql/minikql/mkql_program_builder.h b/ydb/library/yql/minikql/mkql_program_builder.h index 9eb4ac493743..fa45003ae363 100644 --- a/ydb/library/yql/minikql/mkql_program_builder.h +++ b/ydb/library/yql/minikql/mkql_program_builder.h @@ -672,6 +672,7 @@ class TProgramBuilder : public TTypeBuilder { const std::string_view& cluster, const std::string_view& table, TType* returnType); + TRuntimeNode PgToRecord(TRuntimeNode input, const TArrayRef>& members); TRuntimeNode ScalarApply(const TArrayRef& args, const TArrayLambda& handler); diff --git a/ydb/library/yql/minikql/mkql_runtime_version.h b/ydb/library/yql/minikql/mkql_runtime_version.h index e7f39f9b250b..ea9606ffbe21 100644 --- a/ydb/library/yql/minikql/mkql_runtime_version.h +++ b/ydb/library/yql/minikql/mkql_runtime_version.h @@ -24,7 +24,7 @@ namespace NMiniKQL { // 1. Bump this version every time incompatible runtime nodes are introduced. // 2. Make sure you provide runtime node generation for previous runtime versions. #ifndef MKQL_RUNTIME_VERSION -#define MKQL_RUNTIME_VERSION 47U +#define MKQL_RUNTIME_VERSION 48U #endif // History: diff --git a/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp b/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp index 7ed88b35ccb5..4b6034e14f04 100644 --- a/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp +++ b/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp @@ -1304,6 +1304,121 @@ class TPgResolvedMultiCall : public TPgResolvedCallBase { } }; +class TPgToRecord : public TMutableComputationNode { + typedef TMutableComputationNode TBaseComputation; +public: + TPgToRecord( + TComputationMutables& mutables, + IComputationNode* arg, + TStructType* structType, + TVector>&& members + ) + : TBaseComputation(mutables) + , Arg(arg) + , StructType(structType) + , Members(std::move(members)) + , StateIndex(mutables.CurValueIndex++) + { + StructIndicies.resize(Members.size()); + FieldTypes.resize(Members.size()); + for (ui32 i = 0; i < Members.size(); ++i) { + StructIndicies[i] = structType->GetMemberIndex(Members[i].second); + auto itemType = structType->GetMemberType(StructIndicies[i]); + ui32 oid; + if (itemType->IsNull()) { + oid = UNKNOWNOID; + } else { + oid = AS_TYPE(TPgType, itemType)->GetTypeId(); + } + + FieldTypes[i] = &NPg::LookupType(oid); + } + } + + NUdf::TUnboxedValuePod DoCalculate(TComputationContext& compCtx) const { + auto input = Arg->GetValue(compCtx); + auto& state = GetState(compCtx); + + auto elements = input.GetElements(); + TVector elemValues; + if (!elements) { + elemValues.reserve(StructType->GetMembersCount()); + for (ui32 i = 0; i < StructType->GetMembersCount(); ++i) { + elemValues.push_back(input.GetElement(i)); + } + + elements = elemValues.data(); + } + + for (ui32 i = 0; i < Members.size(); ++i) { + auto index = StructIndicies[i]; + if (!elements[index]) { + state.Nulls[i] = true; + } else { + state.Nulls[i] = false; + if (FieldTypes[i]->PassByValue) { + state.Values[i] = ScalarDatumFromPod(elements[index]); + } else { + state.Values[i] = PointerDatumFromPod(elements[index]); + } + } + } + + HeapTuple tuple = heap_form_tuple(state.Desc, state.Values.get(), state.Nulls.get()); + auto result = (HeapTupleHeader) palloc(tuple->t_len); + memcpy(result, tuple->t_data, tuple->t_len); + heap_freetuple(tuple); + return PointerDatumToPod((Datum)result); + } + +private: + void RegisterDependencies() const final { + DependsOn(Arg); + } + + struct TPgToRecordState : public TComputationValue { + TPgToRecordState(TMemoryUsageInfo* memInfo, const TVector>& members, + const TVector& fieldTypes) + : TComputationValue(memInfo) + { + Values.reset(new Datum[members.size()]); + Nulls.reset(new bool[members.size()]); + Desc = CreateTemplateTupleDesc(members.size()); + for (ui32 i = 0; i < members.size(); ++i) { + TupleDescInitEntry(Desc, (AttrNumber) 1 + i, members[i].first.c_str(), fieldTypes[i]->TypeId, -1, 0); + } + + Desc = BlessTupleDesc(Desc); + } + + ~TPgToRecordState() + { + FreeTupleDesc(Desc); + } + + std::unique_ptr Values; + std::unique_ptr Nulls; + TupleDesc Desc; + }; + + TPgToRecordState& GetState(TComputationContext& compCtx) const { + auto& result = compCtx.MutableValues[StateIndex]; + if (!result.HasValue()) { + result = compCtx.HolderFactory.Create(Members, FieldTypes); + } + + return *static_cast(result.AsBoxed().Get()); + } + + + IComputationNode* const Arg; + TStructType* const StructType; + const TVector> Members; + const ui32 StateIndex; + TVector StructIndicies; + TVector FieldTypes; +}; + class TPgCast : public TMutableComputationNode { typedef TMutableComputationNode TBaseComputation; public: @@ -2468,6 +2583,23 @@ TComputationNodeFactory GetPgFactory() { return new TPgTableContent(ctx.Mutables, cluster, table, returnType); } + if (name == "PgToRecord") { + auto structType = AS_TYPE(TStructType, callable.GetInput(0).GetStaticType()); + auto input = LocateNode(ctx.NodeLocator, callable, 0); + TVector> members; + auto tuple = AS_VALUE(TTupleLiteral, callable.GetInput(1)); + MKQL_ENSURE(tuple->GetValuesCount() % 2 == 0, "Malformed names"); + for (ui32 i = 0; i < tuple->GetValuesCount(); i += 2) { + const auto recordFieldData = AS_VALUE(TDataLiteral, tuple->GetValue(i)); + const auto struсtMemberData = AS_VALUE(TDataLiteral, tuple->GetValue(i + 1)); + const TString recordField(recordFieldData->AsValue().AsStringRef()); + const TString struсtMember(struсtMemberData->AsValue().AsStringRef()); + members.push_back({recordField, struсtMember}); + } + + return new TPgToRecord(ctx.Mutables, input, structType, std::move(members)); + } + if (name == "PgResolvedCall") { const auto useContextData = AS_VALUE(TDataLiteral, callable.GetInput(0)); const auto rangeFunctionData = AS_VALUE(TDataLiteral, callable.GetInput(1)); diff --git a/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp b/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp index a7f29b332ae7..ffdc35ab869d 100644 --- a/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp +++ b/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp @@ -2683,7 +2683,7 @@ TMkqlCommonCallableCompiler::TShared::TShared() { return ctx.ProgramBuilder.PgClone(input, dependentNodes); }); - AddCallable("PgTableContent", [](const TExprNode& node, TMkqlBuildContext& ctx) { + AddCallable("PgTableContent", [](const TExprNode& node, TMkqlBuildContext& ctx) { auto returnType = BuildType(node, *node.GetTypeAnn(), ctx.ProgramBuilder); return ctx.ProgramBuilder.PgTableContent( node.Child(0)->Content(), @@ -2691,6 +2691,16 @@ TMkqlCommonCallableCompiler::TShared::TShared() { returnType); }); + AddCallable("PgToRecord", [](const TExprNode& node, TMkqlBuildContext& ctx) { + auto input = MkqlBuildExpr(*node.Child(0), ctx); + TVector> members; + for (auto child : node.Child(1)->Children()) { + members.push_back({child->Head().Content(), child->Tail().Content()}); + } + + return ctx.ProgramBuilder.PgToRecord(input, members); + }); + AddCallable("WithContext", [](const TExprNode& node, TMkqlBuildContext& ctx) { auto input = MkqlBuildExpr(*node.Child(0), ctx); return ctx.ProgramBuilder.WithContext(input, node.Child(1)->Content()); diff --git a/ydb/library/yql/tests/sql/dq_file/part9/canondata/result.json b/ydb/library/yql/tests/sql/dq_file/part9/canondata/result.json index ee67dec90190..97755a149e71 100644 --- a/ydb/library/yql/tests/sql/dq_file/part9/canondata/result.json +++ b/ydb/library/yql/tests/sql/dq_file/part9/canondata/result.json @@ -1683,6 +1683,28 @@ } ], "test.test[pg-range_function_multi_record-default.txt-Results]": [], + "test.test[pg-record_from_table_row-default.txt-Analyze]": [ + { + "checksum": "b4dd508a329723c74293d80f0278c705", + "size": 505, + "uri": "https://{canondata_backend}/1937429/8c415fc988c547984fa23f72063d4859ddd65412/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Analyze_/plan.txt" + } + ], + "test.test[pg-record_from_table_row-default.txt-Debug]": [ + { + "checksum": "354f6fa3bd19b858fa7537772200c7fb", + "size": 527, + "uri": "https://{canondata_backend}/1937429/8c415fc988c547984fa23f72063d4859ddd65412/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Debug_/opt.yql_patched" + } + ], + "test.test[pg-record_from_table_row-default.txt-Plan]": [ + { + "checksum": "b4dd508a329723c74293d80f0278c705", + "size": 505, + "uri": "https://{canondata_backend}/1937429/8c415fc988c547984fa23f72063d4859ddd65412/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Plan_/plan.txt" + } + ], + "test.test[pg-record_from_table_row-default.txt-Results]": [], "test.test[pg-select_agg_gs_cube-default.txt-Analyze]": [ { "checksum": "b4dd508a329723c74293d80f0278c705", diff --git a/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json b/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json index 3b9c290040f2..9a1a192d3375 100644 --- a/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json +++ b/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json @@ -1581,6 +1581,20 @@ "uri": "https://{canondata_backend}/1781765/028f42f897160b53900546b39900217bb2eb9fb1/resource.tar.gz#test.test_pg-pg_in_dict_key_with_stable_pickle-default.txt-Plan_/plan.txt" } ], + "test.test[pg-record_from_table_row-default.txt-Debug]": [ + { + "checksum": "72570482eac43dc72fb808334c10d01b", + "size": 526, + "uri": "https://{canondata_backend}/1924537/4ece22823ee95186ecb519415692146559b02395/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Debug_/opt.yql_patched" + } + ], + "test.test[pg-record_from_table_row-default.txt-Plan]": [ + { + "checksum": "b4dd508a329723c74293d80f0278c705", + "size": 505, + "uri": "https://{canondata_backend}/1924537/4ece22823ee95186ecb519415692146559b02395/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Plan_/plan.txt" + } + ], "test.test[pg-select_case-default.txt-Debug]": [ { "checksum": "ca3e660c6d5689aa9b9b24e7a0d1c79a", diff --git a/ydb/library/yql/tests/sql/sql2yql/canondata/result.json b/ydb/library/yql/tests/sql/sql2yql/canondata/result.json index 4e2849d9de7e..f595f497da1e 100644 --- a/ydb/library/yql/tests/sql/sql2yql/canondata/result.json +++ b/ydb/library/yql/tests/sql/sql2yql/canondata/result.json @@ -11353,6 +11353,13 @@ "uri": "https://{canondata_backend}/1936947/feceb71e6c925b39a34ab09e3bcd03d162bc6b1e/resource.tar.gz#test_sql2yql.test_pg-range_function_scalar_/sql.yql" } ], + "test_sql2yql.test[pg-record_from_table_row]": [ + { + "checksum": "252126909d824d05cdd65844f8429313", + "size": 732, + "uri": "https://{canondata_backend}/1937429/6c80ea12421e08c27b3e211492dc22d34e4429ce/resource.tar.gz#test_sql2yql.test_pg-record_from_table_row_/sql.yql" + } + ], "test_sql2yql.test[pg-select_agg]": [ { "checksum": "e6dc3141786c94a8cc4c07b9c88f6465", diff --git a/ydb/library/yql/tests/sql/suites/pg/record_from_table_row.sql b/ydb/library/yql/tests/sql/suites/pg/record_from_table_row.sql new file mode 100644 index 000000000000..5133380ec604 --- /dev/null +++ b/ydb/library/yql/tests/sql/suites/pg/record_from_table_row.sql @@ -0,0 +1,4 @@ +--!syntax_pg +SELECT row_to_json(TR) +FROM (select 'foo' as y, 1 as x) tr + diff --git a/ydb/library/yql/tests/sql/yt_native_file/part9/canondata/result.json b/ydb/library/yql/tests/sql/yt_native_file/part9/canondata/result.json index 7dee8617f8ca..64433e92aa5e 100644 --- a/ydb/library/yql/tests/sql/yt_native_file/part9/canondata/result.json +++ b/ydb/library/yql/tests/sql/yt_native_file/part9/canondata/result.json @@ -1622,6 +1622,27 @@ "uri": "https://{canondata_backend}/1784117/6620b590bc9922dc9aac4760f7b49fcc4d5b74cc/resource.tar.gz#test.test_pg-range_function_multi_record-default.txt-Results_/results.txt" } ], + "test.test[pg-record_from_table_row-default.txt-Debug]": [ + { + "checksum": "60ef754fb2615ead4ed1c0273289e69f", + "size": 471, + "uri": "https://{canondata_backend}/1924537/0a1091e0cd385f335469f9ed9f6632773d61c7ff/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Debug_/opt.yql" + } + ], + "test.test[pg-record_from_table_row-default.txt-Plan]": [ + { + "checksum": "b4dd508a329723c74293d80f0278c705", + "size": 505, + "uri": "https://{canondata_backend}/1924537/0a1091e0cd385f335469f9ed9f6632773d61c7ff/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Plan_/plan.txt" + } + ], + "test.test[pg-record_from_table_row-default.txt-Results]": [ + { + "checksum": "92f2a28df037d923273f89c97d4378b1", + "size": 688, + "uri": "https://{canondata_backend}/1924537/0a1091e0cd385f335469f9ed9f6632773d61c7ff/resource.tar.gz#test.test_pg-record_from_table_row-default.txt-Results_/results.txt" + } + ], "test.test[pg-select_agg_gs_cube-default.txt-Debug]": [ { "checksum": "889c434e89bc818daec09bacf477debf",