diff options
| author | atarasov5 <[email protected]> | 2026-07-17 11:28:08 +0300 |
|---|---|---|
| committer | atarasov5 <[email protected]> | 2026-07-17 18:57:11 +0300 |
| commit | 0e52f04caa16030b7e49090548b32fb50be2ef81 (patch) | |
| tree | 5cb5ee4fdfc60626e08275b6a82bb9c1a98de74a | |
| parent | 031e2b7b3e7e5e9a45058b929173e2c64384d4d3 (diff) | |
YQL-21315: Block variant item implementation
BlockVariantItem implementation
commit_hash:f35a597dee3dc67ebc5be599ed9d379d7ad57802
34 files changed, 1047 insertions, 8 deletions
diff --git a/yql/essentials/core/peephole_opt/yql_opt_peephole_physical.cpp b/yql/essentials/core/peephole_opt/yql_opt_peephole_physical.cpp index e3878dc97f3..b4049e8b405 100644 --- a/yql/essentials/core/peephole_opt/yql_opt_peephole_physical.cpp +++ b/yql/essentials/core/peephole_opt/yql_opt_peephole_physical.cpp @@ -6478,7 +6478,8 @@ private: bool isSuitableGuess = NKikimr::NMiniKQL::RuntimeVersion >= 79 && node->IsCallable("Guess"); bool isSuitableWay = NKikimr::NMiniKQL::RuntimeVersion >= 80 && node->IsCallable("Way"); bool isSuitableVariant = NKikimr::NMiniKQL::RuntimeVersion >= 81 && node->IsCallable("Variant"); - if (node->IsList() || rewriteAsIs || isSuitableGuess || isSuitableWay || isSuitableVariant || + bool isSuitableVariantItem = NKikimr::NMiniKQL::RuntimeVersion >= 82 && node->IsCallable("VariantItem"); + if (node->IsList() || rewriteAsIs || isSuitableGuess || isSuitableWay || isSuitableVariant || isSuitableVariantItem || node->IsCallable({"DecimalMul", "DecimalDiv", "DecimalMod", "And", "Or", "Xor", "Not", "Coalesce", "Exists", "If", "Just", "AsStruct", "Member", "Nth", "ToPg", "FromPg", "PgResolvedCall", "PgResolvedOp"})) { if (node->IsCallable() && !IsSupportedAsBlockType(node->Pos(), *node->GetTypeAnn(), Ctx_, Types_, /*reportUnspported=*/true)) { YQL_CLOG(TRACE, CorePeepHole) << Log(node) << "Type are not supported"; diff --git a/yql/essentials/core/type_ann/type_ann_blocks.cpp b/yql/essentials/core/type_ann/type_ann_blocks.cpp index dd5e3dae0a4..755c6704afb 100644 --- a/yql/essentials/core/type_ann/type_ann_blocks.cpp +++ b/yql/essentials/core/type_ann/type_ann_blocks.cpp @@ -59,6 +59,32 @@ bool EnsurePayloadMatchesAlternative(const TExprNode& payloadNode, const TTypeAn return false; } +const TTypeAnnotationNode* ResolveCommonVariantAlternativeType(const TExprNode& input, const TVariantExprType& variantType, TContext& ctx) { + if (variantType.GetUnderlyingType()->GetKind() == ETypeAnnotationKind::Tuple) { + auto tupleType = variantType.GetUnderlyingType()->Cast<TTupleExprType>(); + auto firstType = tupleType->GetItems()[0]; + for (size_t i = 1; i < tupleType->GetSize(); ++i) { + if (firstType != tupleType->GetItems()[i]) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(input.Pos()), TStringBuilder() + << "All Variant item types should be equal: " << GetTypeDiff(*firstType, *tupleType->GetItems()[i]))); + return nullptr; + } + } + return firstType; + } else { + auto structType = variantType.GetUnderlyingType()->Cast<TStructExprType>(); + auto firstType = structType->GetItems()[0]->GetItemType(); + for (size_t i = 1; i < structType->GetSize(); ++i) { + if (firstType != structType->GetItems()[i]->GetItemType()) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(input.Pos()), TStringBuilder() + << "All Variant item types should be equal: " << GetTypeDiff(*firstType, *structType->GetItems()[i]->GetItemType()))); + return nullptr; + } + } + return firstType; + } +} + } // namespace IGraphTransformer::TStatus AsScalarWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TExtContext& ctx) { @@ -502,6 +528,38 @@ IGraphTransformer::TStatus BlockVariantWrapper(const TExprNode::TPtr& input, TEx return IGraphTransformer::TStatus::Ok; } +IGraphTransformer::TStatus BlockVariantItemWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) { + Y_UNUSED(output); + if (!EnsureArgsCount(*input, 1, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + auto variantNode = input->Child(0); + if (!EnsureBlockOrScalarType(*variantNode, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + bool isScalar; + const TTypeAnnotationNode* itemType = GetBlockItemType(*variantNode->GetTypeAnn(), isScalar); + + bool isOptional = itemType->GetKind() == ETypeAnnotationKind::Optional; + const TTypeAnnotationNode* innerItemType = isOptional ? itemType->Cast<TOptionalExprType>()->GetItemType() : itemType; + if (!EnsureVariantType(variantNode->Pos(), *innerItemType, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + auto variantType = innerItemType->Cast<TVariantExprType>(); + + const TTypeAnnotationNode* alternativeType = ResolveCommonVariantAlternativeType(*input, *variantType, ctx); + if (!alternativeType) { + return IGraphTransformer::TStatus::Error; + } + + if (isOptional) { + alternativeType = ctx.Expr.MakeType<TOptionalExprType>(alternativeType); + } + input->SetTypeAnn(MakeBlockOrScalarType(alternativeType, isScalar, ctx.Expr)); + return IGraphTransformer::TStatus::Ok; +} + IGraphTransformer::TStatus BlockIfWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) { Y_UNUSED(output); if (!EnsureArgsCount(*input, 3U, ctx.Expr)) { diff --git a/yql/essentials/core/type_ann/type_ann_blocks.h b/yql/essentials/core/type_ann/type_ann_blocks.h index 44adc07d30a..781322fc345 100644 --- a/yql/essentials/core/type_ann/type_ann_blocks.h +++ b/yql/essentials/core/type_ann/type_ann_blocks.h @@ -19,6 +19,7 @@ namespace NYql::NTypeAnnImpl { IGraphTransformer::TStatus BlockGuessWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockWayWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockVariantWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); + IGraphTransformer::TStatus BlockVariantItemWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockIfWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockJustWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockAsStructWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); diff --git a/yql/essentials/core/type_ann/type_ann_core.cpp b/yql/essentials/core/type_ann/type_ann_core.cpp index 399e1254315..3235cbfb033 100644 --- a/yql/essentials/core/type_ann/type_ann_core.cpp +++ b/yql/essentials/core/type_ann/type_ann_core.cpp @@ -16522,6 +16522,7 @@ template <NKikimr::NUdf::EDataSlot DataSlot> Functions["BlockGuess"] = &BlockGuessWrapper; Functions["BlockWay"] = &BlockWayWrapper; Functions["BlockVariant"] = &BlockVariantWrapper; + Functions["BlockVariantItem"] = &BlockVariantItemWrapper; Functions["BlockIf"] = &BlockIfWrapper; Functions["BlockJust"] = &BlockJustWrapper; Functions["BlockAsStruct"] = &BlockAsStructWrapper; diff --git a/yql/essentials/minikql/comp_nodes/mkql_block_variant_item.cpp b/yql/essentials/minikql/comp_nodes/mkql_block_variant_item.cpp new file mode 100644 index 00000000000..82db82fa17b --- /dev/null +++ b/yql/essentials/minikql/comp_nodes/mkql_block_variant_item.cpp @@ -0,0 +1,125 @@ +#include "mkql_block_variant_item.h" + +#include <yql/essentials/minikql/computation/mkql_block_impl.h> +#include <yql/essentials/minikql/computation/mkql_block_reader.h> +#include <yql/essentials/minikql/computation/mkql_computation_node_holders.h> +#include <yql/essentials/minikql/mkql_node_builder.h> +#include <yql/essentials/minikql/mkql_node_cast.h> +#include <yql/essentials/public/udf/arrow/block_builder.h> +#include <yql/essentials/public/udf/arrow/block_reader.h> + +namespace NKikimr::NMiniKQL { + +namespace { + +template <bool IsOptional> +class TVariantItemBlockExec { +public: + class TVariantItemKernelState: public arrow::compute::KernelState { + public: + explicit TVariantItemKernelState(TType* inputItemType) + : Reader_(MakeBlockReader(TTypeInfoHelper(), inputItemType)) + { + } + + IBlockReader& GetReader() { + return *Reader_; + } + + private: + std::unique_ptr<IBlockReader> Reader_; + }; + + explicit TVariantItemBlockExec(TType* inputItemType, TType* resultItemType) + : InputItemType_(inputItemType) + , ResultItemType_(resultItemType) + { + } + + arrow::Status Exec(arrow::compute::KernelContext* ctx, const arrow::compute::ExecBatch& batch, arrow::Datum* res) const { + auto& reader = static_cast<TVariantItemKernelState&>(*ctx->state()).GetReader(); + const arrow::Datum& variantDatum = batch.values[0]; + + if (variantDatum.is_scalar()) { + *res = ConvertScalar(ResultItemType_, + ComputeOutputItem(reader.GetScalarItem(*variantDatum.scalar())), + *ctx->memory_pool()); + return arrow::Status::OK(); + } + + MKQL_ENSURE(variantDatum.is_array(), "Expected array datum"); + const auto& variantArrayData = variantDatum.array(); + const size_t length = static_cast<size_t>(variantArrayData->length); + auto builder = NYql::NUdf::MakeArrayBuilder(TTypeInfoHelper(), ResultItemType_, *ctx->memory_pool(), length, /*pgBuilder=*/nullptr); + for (size_t i = 0; i < length; ++i) { + builder->Add(ComputeOutputItem(reader.GetItem(*variantArrayData, i))); + } + *res = builder->Build(/*finish=*/true); + return arrow::Status::OK(); + } + +private: + TBlockItem ComputeOutputItem(TBlockItem blockItem) const { + if constexpr (IsOptional) { + if (!blockItem) { + return TBlockItem{}; + } + return blockItem.GetVariantItem().MakeOptional(); + } else { + return blockItem.GetVariantItem(); + } + } + + TType* const InputItemType_; + TType* const ResultItemType_; +}; + +template <bool IsOptional> +std::shared_ptr<arrow::compute::ScalarKernel> MakeBlockVariantItemKernel(const TVector<TType*>& argTypes, + TType* resultType, + TType* inputItemType) { + using TExec = TVariantItemBlockExec<IsOptional>; + auto exec = std::make_shared<TExec>( + inputItemType, + AS_TYPE(TBlockType, resultType)->GetItemType()); + auto kernel = std::make_shared<arrow::compute::ScalarKernel>( + ConvertToInputTypes(argTypes), + ConvertToOutputType(resultType), + [exec](arrow::compute::KernelContext* ctx, const arrow::compute::ExecBatch& batch, arrow::Datum* res) { + return exec->Exec(ctx, batch, res); + }); + kernel->null_handling = arrow::compute::NullHandling::COMPUTED_NO_PREALLOCATE; + kernel->mem_allocation = arrow::compute::MemAllocation::NO_PREALLOCATE; + kernel->init = [inputItemType](arrow::compute::KernelContext*, const arrow::compute::KernelInitArgs&) { + return arrow::Result(std::make_unique<typename TExec::TVariantItemKernelState>(inputItemType)); + }; + return kernel; +} + +} // namespace + +IComputationNode* WrapBlockVariantItem(TCallable& callable, const TComputationNodeFactoryContext& ctx) { + MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected 1 argument"); + + auto blockType = AS_TYPE(TBlockType, callable.GetInput(0).GetStaticType()); + auto inputItemType = blockType->GetItemType(); + + bool isOptional; + auto variantItemType = UnpackOptional(inputItemType, isOptional); + AS_TYPE(TVariantType, variantItemType); + + auto variantCompute = LocateNode(ctx.NodeLocator, callable, 0); + TComputationNodePtrVector argsNodes = {variantCompute}; + TVector<TType*> argsTypes = {blockType}; + + auto resultType = callable.GetType()->GetReturnType(); + + auto kernel = isOptional + ? MakeBlockVariantItemKernel<true>(argsTypes, resultType, inputItemType) + : MakeBlockVariantItemKernel<false>(argsTypes, resultType, inputItemType); + + return new TBlockFuncNode(ctx.Mutables, ctx.RuntimeSettings->DatumValidation.Get(), + callable.GetType()->GetName(), std::move(argsNodes), argsTypes, resultType, *kernel, kernel); +} + +} // namespace NKikimr::NMiniKQL diff --git a/yql/essentials/minikql/comp_nodes/mkql_block_variant_item.h b/yql/essentials/minikql/comp_nodes/mkql_block_variant_item.h new file mode 100644 index 00000000000..78017ada20f --- /dev/null +++ b/yql/essentials/minikql/comp_nodes/mkql_block_variant_item.h @@ -0,0 +1,9 @@ +#pragma once + +#include <yql/essentials/minikql/computation/mkql_computation_node.h> + +namespace NKikimr::NMiniKQL { + +IComputationNode* WrapBlockVariantItem(TCallable& callable, const TComputationNodeFactoryContext& ctx); + +} // namespace NKikimr::NMiniKQL diff --git a/yql/essentials/minikql/comp_nodes/mkql_factory.cpp b/yql/essentials/minikql/comp_nodes/mkql_factory.cpp index f49b942dd7a..2f1fc15cc23 100644 --- a/yql/essentials/minikql/comp_nodes/mkql_factory.cpp +++ b/yql/essentials/minikql/comp_nodes/mkql_factory.cpp @@ -14,6 +14,7 @@ #include "mkql_block_getelem.h" #include "mkql_block_guess.h" #include "mkql_block_variant.h" +#include "mkql_block_variant_item.h" #include "mkql_block_way.h" #include "mkql_block_if.h" #include "mkql_block_just.h" @@ -313,6 +314,7 @@ struct TCallableComputationNodeBuilderFuncMapFiller { {"BlockExists", &WrapBlockExists}, {"BlockGuess", &WrapBlockGuess}, {"BlockVariant", &WrapBlockVariant}, + {"BlockVariantItem", &WrapBlockVariantItem}, {"BlockWay", &WrapBlockWay}, {"BlockIf", &WrapBlockIf}, {"BlockAnd", &WrapBlockAnd}, diff --git a/yql/essentials/minikql/comp_nodes/mkql_varitem.cpp b/yql/essentials/minikql/comp_nodes/mkql_varitem.cpp index 90e0c02bb60..ecde4b30f8a 100644 --- a/yql/essentials/minikql/comp_nodes/mkql_varitem.cpp +++ b/yql/essentials/minikql/comp_nodes/mkql_varitem.cpp @@ -24,11 +24,14 @@ public: NUdf::TUnboxedValuePod DoCalculate(TComputationContext& compCtx) const { auto var = VarNode->GetValue(compCtx); - if (IsOptional && !var) { - return NUdf::TUnboxedValuePod(); + if constexpr (IsOptional) { + if (!var) { + return NUdf::TUnboxedValuePod(); + } + return var.Release().GetVariantItem().Release().MakeOptional(); + } else { + return var.Release().GetVariantItem().Release(); } - - return var.Release().GetVariantItem().Release(); } #ifndef MKQL_DISABLE_CODEGEN @@ -40,7 +43,7 @@ public: const auto var = GetNodeValue(VarNode, ctx, block); const auto done = BasicBlock::Create(context, "done", ctx.Func); - if (IsOptional) { + if constexpr (IsOptional) { const auto good = BasicBlock::Create(context, "good", ctx.Func); const auto none = BasicBlock::Create(context, "none", ctx.Func); @@ -66,12 +69,20 @@ public: const uint64_t init[] = {0xFFFFFFFFFFFFFFFFULL, 0x3FFFFFFFFFFFFFFULL}; const auto mask = ConstantInt::get(valueType, APInt(128, 2, init)); const auto clean = BinaryOperator::CreateAnd(var, mask, "clean", block); - new StoreInst(clean, pointer, block); + if constexpr (IsOptional) { + new StoreInst(MakeOptional(context, clean, block), pointer, block); + } else { + new StoreInst(clean, pointer, block); + } ValueAddRef(this->RepresentationKind_, pointer, ctx, block); BranchInst::Create(done, block); block = box; CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetVariantItem>(pointer, var, ctx.Codegen, block); + if constexpr (IsOptional) { + const auto load = new LoadInst(valueType, pointer, "load", block); + new StoreInst(MakeOptional(context, load, block), pointer, block); + } BranchInst::Create(done, block); block = done; diff --git a/yql/essentials/minikql/comp_nodes/ut/mkql_block_variant_item_ut.cpp b/yql/essentials/minikql/comp_nodes/ut/mkql_block_variant_item_ut.cpp new file mode 100644 index 00000000000..34042224cc4 --- /dev/null +++ b/yql/essentials/minikql/comp_nodes/ut/mkql_block_variant_item_ut.cpp @@ -0,0 +1,312 @@ +#include <yql/essentials/minikql/comp_nodes/mkql_block_variant_item.h> + +#include <yql/essentials/minikql/comp_nodes/ut/mkql_block_test_helper.h> +#include <yql/essentials/minikql/comp_nodes/ut/mkql_computation_node_ut.h> +#include <yql/essentials/minikql/mkql_type_builder.h> +#include <yql/essentials/utils/random_data_generator/random_data_generator.h> + +#include <library/cpp/random_provider/random_provider.h> + +#include <tuple> +#include <variant> + +namespace NKikimr::NMiniKQL { + +using namespace NTest; + +namespace { + +constexpr size_t LargeStringLength = MaxBlockSizeInBytes / 10; + +template <typename TInputData, typename TExpectedData> +void TestBlockVariantItem(const TVector<TInputData>& data, const TVector<TExpectedData>& expected) { + TBlockHelper().TestKernelFuzzied(data, expected, [](TSetup<false>& setup, TRuntimeNode variantValue) { + return setup.PgmBuilder->BlockVariantItem(variantValue); + }); +} + +template <typename... Ts> +auto ExtractCommonAlternative(const std::variant<Ts...>& variant) { + return std::visit([](const auto& alternativeValue) { return alternativeValue; }, variant); +} + +template <typename TVariant> +TVector<decltype(ExtractCommonAlternative(std::declval<TVariant>()))> ExtractCommonAlternatives(const TVector<TVariant>& data) { + TVector<decltype(ExtractCommonAlternative(std::declval<TVariant>()))> expected; + expected.reserve(data.size()); + for (const auto& variant : data) { + expected.push_back(ExtractCommonAlternative(variant)); + } + return expected; +} + +} // namespace + +Y_UNIT_TEST_SUITE(TMiniKQLBlockVariantItemTest) { + +Y_UNIT_TEST(TupleVariant_Ui32_TwoAlternatives) { + using TVariant = std::variant<ui32, ui32>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, 1u), + TVariant(std::in_place_index<1>, 2u), + TVariant(std::in_place_index<0>, 3u), + }; + TVector<ui32> expected = {1u, 2u, 3u}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_Ui32_ThreeAlternatives) { + using TVariant = std::variant<ui32, ui32, ui32>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, 1u), + TVariant(std::in_place_index<1>, 2u), + TVariant(std::in_place_index<2>, 3u), + TVariant(std::in_place_index<0>, 4u), + }; + TVector<ui32> expected = {1u, 2u, 3u, 4u}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_TString_TwoAlternatives) { + using TVariant = std::variant<TString, TString>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, TString{"hello"}), + TVariant(std::in_place_index<1>, TString{"world"}), + TVariant(std::in_place_index<0>, TString{""}), + }; + TVector<TString> expected = {"hello", "world", ""}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_NestedTuple_TwoAlternatives) { + using TInner = std::tuple<ui32, TString>; + using TVariant = std::variant<TInner, TInner>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, TInner{1u, "a"}), + TVariant(std::in_place_index<1>, TInner{2u, "b"}), + TVariant(std::in_place_index<0>, TInner{3u, "c"}), + }; + TVector<TInner> expected = {TInner{1u, "a"}, TInner{2u, "b"}, TInner{3u, "c"}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_NestedVariant_TwoAlternatives) { + using TInner = std::variant<ui32, ui32>; + using TVariant = std::variant<TInner, TInner>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, TInner(std::in_place_index<0>, 1u)), + TVariant(std::in_place_index<1>, TInner(std::in_place_index<1>, 2u)), + TVariant(std::in_place_index<0>, TInner(std::in_place_index<1>, 3u)), + }; + TVector<TInner> expected = ExtractCommonAlternatives(data); + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_OptionalInnerUi32_TwoAlternatives) { + using TInner = TMaybe<ui32>; + using TVariant = std::variant<TInner, TInner>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, TInner{10u}), + TVariant(std::in_place_index<1>, TInner{}), + TVariant(std::in_place_index<0>, TInner{20u}), + }; + TVector<TMaybe<ui32>> expected = {TInner{10u}, TInner{}, TInner{20u}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_OptionalInnerString_TwoAlternatives) { + using TInner = TMaybe<TString>; + using TVariant = std::variant<TInner, TInner>; + TVector<TVariant> data = { + TVariant(std::in_place_index<0>, TInner{"first"}), + TVariant(std::in_place_index<1>, TInner{}), + TVariant(std::in_place_index<1>, TInner{"second"}), + }; + TVector<TMaybe<TString>> expected = {TInner{"first"}, TInner{}, TInner{"second"}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalTupleVariant_Ui32_NullRows) { + using TVariant = std::variant<ui32, ui32>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<0>, 1u)}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, 3u)}, + }; + TVector<TMaybe<ui32>> expected = {ui32{1u}, Nothing(), ui32{3u}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalTupleVariant_TString_MixedNull) { + using TVariant = std::variant<TString, TString>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<0>, TString{"hello"})}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TString{"world"})}, + TMaybe<TVariant>{}, + }; + TVector<TMaybe<TString>> expected = {TString{"hello"}, Nothing(), TString{"world"}, Nothing()}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalTupleVariant_NestedTuple_MixedNull) { + using TInner = std::tuple<ui32, TString>; + using TVariant = std::variant<TInner, TInner>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<0>, TInner{1u, "a"})}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{2u, "b"})}, + }; + TVector<TMaybe<TInner>> expected = {TInner{1u, "a"}, Nothing(), TInner{2u, "b"}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalTupleVariant_OptionalInnerUi32_MixedNull) { + using TInner = TMaybe<ui32>; + using TVariant = std::variant<TInner, TInner>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<0>, TInner{10u})}, + TMaybe<TVariant>{TVariant(std::in_place_index<0>, TInner{})}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{20u})}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{})}, + }; + TVector<TMaybe<TInner>> expected = { + TMaybe<TInner>{TInner{10u}}, + TMaybe<TInner>{TInner{}}, + TMaybe<TInner>{}, + TMaybe<TInner>{TInner{20u}}, + TMaybe<TInner>{TInner{}}, + }; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(StructVariant_Ui32_TwoMembers) { + using TMemberA = NTest::TStructMember<"a", ui32>; + using TMemberB = NTest::TStructMember<"b", ui32>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB>; + + TVector<TVariant> data = {TVariant{TMemberA{1}}, TVariant{TMemberB{2}}, TVariant{TMemberA{3}}}; + TVector<ui32> expected = {1u, 2u, 3u}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(StructVariant_Ui32_ThreeMembers) { + using TMemberA = NTest::TStructMember<"a", ui32>; + using TMemberB = NTest::TStructMember<"b", ui32>; + using TMemberC = NTest::TStructMember<"c", ui32>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB, TMemberC>; + + TVector<TVariant> data = {TVariant{TMemberA{1}}, TVariant{TMemberB{2}}, TVariant{TMemberC{3}}, TVariant{TMemberA{4}}}; + TVector<ui32> expected = {1u, 2u, 3u, 4u}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(StructVariant_TString_TwoMembers) { + using TMemberA = NTest::TStructMember<"a", TString>; + using TMemberB = NTest::TStructMember<"b", TString>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB>; + + TVector<TVariant> data = {TVariant{TMemberA{"hello"}}, TVariant{TMemberB{"world"}}, TVariant{TMemberA{""}}}; + TVector<TString> expected = {"hello", "world", ""}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(StructVariant_NestedTuple_TwoMembers) { + using TInner = std::tuple<ui32, TString>; + using TMemberA = NTest::TStructMember<"a", TInner>; + using TMemberB = NTest::TStructMember<"b", TInner>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB>; + + TVector<TVariant> data = {TVariant{TMemberA{TInner{1u, "a"}}}, TVariant{TMemberB{TInner{2u, "b"}}}}; + TVector<TInner> expected = {TInner{1u, "a"}, TInner{2u, "b"}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalStructVariant_Ui32_MixedNull) { + using TMemberA = NTest::TStructMember<"a", ui32>; + using TMemberB = NTest::TStructMember<"b", ui32>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB>; + + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{TMemberA{1}}}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant{TMemberB{2}}}, + }; + TVector<TMaybe<ui32>> expected = {ui32{1u}, Nothing(), ui32{2u}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalStructVariant_TString_MixedNull) { + using TMemberA = NTest::TStructMember<"a", TString>; + using TMemberB = NTest::TStructMember<"b", TString>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB>; + + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{TMemberA{"hello"}}}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant{TMemberB{"world"}}}, + }; + TVector<TMaybe<TString>> expected = {TString{"hello"}, Nothing(), TString{"world"}}; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(OptionalStructVariant_OptionalInnerUi32_MixedNull) { + using TInner = TMaybe<ui32>; + using TMemberA = NTest::TStructMember<"a", TInner>; + using TMemberB = NTest::TStructMember<"b", TInner>; + using TVariant = NTest::TStructVariant<TMemberA, TMemberB>; + + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{TMemberA{TInner{10u}}}}, + TMaybe<TVariant>{TVariant{TMemberA{TInner{}}}}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant{TMemberB{TInner{20u}}}}, + TMaybe<TVariant>{TVariant{TMemberB{TInner{}}}}, + }; + TVector<TMaybe<TInner>> expected = { + TMaybe<TInner>{TInner{10u}}, + TMaybe<TInner>{TInner{}}, + TMaybe<TInner>{}, + TMaybe<TInner>{TInner{20u}}, + TMaybe<TInner>{TInner{}}, + }; + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_Ui32_Fuzzied) { + using TVariant = std::variant<ui32, ui32>; + auto rng = CreateDeterministicRandomProvider(200); + const TVector<TVariant> data = NYql::GenerateRandomData<TVariant>(rng, 7); + const TVector<ui32> expected = ExtractCommonAlternatives(data); + TestBlockVariantItem(data, expected); +} + +Y_UNIT_TEST(TupleVariant_LargeString_ChunkedOutput) { + using TVariant = std::variant<TString, TString>; + auto rng = CreateDeterministicRandomProvider(201); + TBlockHelper helper; + + helper.WithScopedFuzzers([&]() { + const NYql::TGeneratorSettings<TVariant> settings{ + .Weights = {1.0, 1.0}, + .InnerSettings = { + NYql::TGeneratorSettings<TString>{.MinSize = 0, .MaxSize = LargeStringLength}, + NYql::TGeneratorSettings<TString>{.MinSize = 0, .MaxSize = LargeStringLength}, + }, + }; + const TVector<TVariant> data = NYql::GenerateRandomData<TVariant>(rng, settings, 50); + const TVector<TString> expected = ExtractCommonAlternatives(data); + + helper.RunNodeOverWideStream( + expected, + [](TSetup<false>& setup, TRuntimeNode variantBlock) { + return setup.PgmBuilder->BlockVariantItem(variantBlock); + }, + data); + }); +} + +} // Y_UNIT_TEST_SUITE(TMiniKQLBlockVariantItemTest) + +} // namespace NKikimr::NMiniKQL diff --git a/yql/essentials/minikql/comp_nodes/ut/mkql_variant_ut.cpp b/yql/essentials/minikql/comp_nodes/ut/mkql_variant_ut.cpp index 83652eb40d8..81083d6fa72 100644 --- a/yql/essentials/minikql/comp_nodes/ut/mkql_variant_ut.cpp +++ b/yql/essentials/minikql/comp_nodes/ut/mkql_variant_ut.cpp @@ -8,6 +8,29 @@ namespace NKikimr { namespace NMiniKQL { +namespace { + +template <typename T, size_t> +using TRepeatedAlternative = T; + +template <typename T, size_t... Indices> +auto MakeRepeatedVariant(std::index_sequence<Indices...>) -> std::variant<TRepeatedAlternative<T, Indices>...>; + +template <typename T, size_t Count> +using TRepeatedVariant = decltype(MakeRepeatedVariant<T>(std::make_index_sequence<Count>{})); + +template <bool LLVM, typename TInputData, typename TExpectedData> +void TestVariantItemRowWise(TSetup<LLVM>& setup, const TVector<TInputData>& data, const TVector<TExpectedData>& expected) { + TProgramBuilder& pb = *setup.PgmBuilder; + const auto list = NTest::ConvertValueToLiteralNode(pb, data); + const auto pgmReturn = pb.Map(list, [&](TRuntimeNode item) { return pb.VariantItem(item); }); + + const auto graph = setup.BuildGraph(pgmReturn); + AssertUnboxedValueElementEqual(graph->GetValue(), expected); +} + +} // namespace + Y_UNIT_TEST_SUITE(TMiniKQLVariantTest) { Y_UNIT_TEST_LLVM(TestGuessTuple) { TSetup<LLVM> setup; @@ -365,6 +388,140 @@ Y_UNIT_TEST_LLVM(TestItemInMap) { UNIT_ASSERT(!iterator.Next(item)); } +Y_UNIT_TEST_LLVM(TestVariantItemTupleOptionalInnerOptional) { + TSetup<LLVM> setup; + + using TInner = TMaybe<ui32>; + using TVariant = std::variant<TInner, TInner>; + const TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<0>, TInner{10U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<0>, TInner{})}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{20U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{})}, + }; + + TestVariantItemRowWise(setup, data, + TVector<TMaybe<TMaybe<ui32>>>{ + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{10U}}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{}}, + TMaybe<TMaybe<ui32>>{}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{20U}}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{}}, + }); +} + +Y_UNIT_TEST_LLVM(TestVariantItemTupleOptionalInnerOptional65Alternatives) { + TSetup<LLVM> setup; + + using TInner = TMaybe<ui32>; + using TVariant = TRepeatedVariant<TInner, 65>; + const TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{10U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, TInner{})}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant(std::in_place_index<7>, TInner{20U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<7>, TInner{})}, + TMaybe<TVariant>{TVariant(std::in_place_index<64>, TInner{30U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<64>, TInner{})}, + }; + + TestVariantItemRowWise(setup, data, + TVector<TMaybe<TMaybe<ui32>>>{ + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{10U}}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{}}, + TMaybe<TMaybe<ui32>>{}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{20U}}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{}}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{30U}}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{}}, + }); +} + +Y_UNIT_TEST_LLVM(TestVariantItemOptionalVariantTwoAlternatives) { + TSetup<LLVM> setup; + + using TVariant = std::variant<ui32, ui32>; + const TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<0>, ui32{10U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<1>, ui32{20U})}, + TMaybe<TVariant>{}, + }; + + TestVariantItemRowWise(setup, data, + TVector<TMaybe<ui32>>{ + TMaybe<ui32>{10U}, + TMaybe<ui32>{20U}, + Nothing(), + }); +} + +Y_UNIT_TEST_LLVM(TestVariantItemOptionalVariant65Alternatives) { + TSetup<LLVM> setup; + + using TVariant = TRepeatedVariant<ui32, 65>; + const TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant(std::in_place_index<1>, ui32{10U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<7>, ui32{20U})}, + TMaybe<TVariant>{TVariant(std::in_place_index<64>, ui32{30U})}, + TMaybe<TVariant>{}, + }; + + TestVariantItemRowWise(setup, data, + TVector<TMaybe<ui32>>{ + TMaybe<ui32>{10U}, + TMaybe<ui32>{20U}, + TMaybe<ui32>{30U}, + Nothing(), + }); +} + +Y_UNIT_TEST_LLVM(TestVariantItemVariantOptionalItemTwoAlternatives) { + TSetup<LLVM> setup; + + using TInner = TMaybe<ui32>; + using TVariant = std::variant<TInner, TInner>; + const TVector<TVariant> data = { + TVariant(std::in_place_index<0>, TInner{10U}), + TVariant(std::in_place_index<0>, TInner{}), + TVariant(std::in_place_index<1>, TInner{20U}), + TVariant(std::in_place_index<1>, TInner{}), + }; + + TestVariantItemRowWise(setup, data, + TVector<TMaybe<ui32>>{ + TMaybe<ui32>{10U}, + TMaybe<ui32>{}, + TMaybe<ui32>{20U}, + TMaybe<ui32>{}, + }); +} + +Y_UNIT_TEST_LLVM(TestVariantItemVariantOptionalItem65Alternatives) { + TSetup<LLVM> setup; + + using TInner = TMaybe<ui32>; + using TVariant = TRepeatedVariant<TInner, 65>; + const TVector<TVariant> data = { + TVariant(std::in_place_index<1>, TInner{10U}), + TVariant(std::in_place_index<1>, TInner{}), + TVariant(std::in_place_index<7>, TInner{20U}), + TVariant(std::in_place_index<7>, TInner{}), + TVariant(std::in_place_index<64>, TInner{30U}), + TVariant(std::in_place_index<64>, TInner{}), + }; + + TestVariantItemRowWise(setup, data, + TVector<TMaybe<ui32>>{ + TMaybe<ui32>{10U}, + TMaybe<ui32>{}, + TMaybe<ui32>{20U}, + TMaybe<ui32>{}, + TMaybe<ui32>{30U}, + TMaybe<ui32>{}, + }); +} + Y_UNIT_TEST_LLVM(TestGuessInMap) { TSetup<LLVM> setup; TProgramBuilder& pb = *setup.PgmBuilder; diff --git a/yql/essentials/minikql/comp_nodes/ut/ya.make.inc b/yql/essentials/minikql/comp_nodes/ut/ya.make.inc index 7cacc9f952a..9ff32b04877 100644 --- a/yql/essentials/minikql/comp_nodes/ut/ya.make.inc +++ b/yql/essentials/minikql/comp_nodes/ut/ya.make.inc @@ -43,6 +43,7 @@ SET(ORIG_SOURCES mkql_block_variant_ut.cpp mkql_block_uuid_ut.cpp mkql_block_dynumber_ut.cpp + mkql_block_variant_item_ut.cpp mkql_block_variant_node_ut.cpp mkql_blocks_ut.cpp mkql_callable_ut.cpp diff --git a/yql/essentials/minikql/comp_nodes/ya.make.inc b/yql/essentials/minikql/comp_nodes/ya.make.inc index 1386f6b5866..224e9803b43 100644 --- a/yql/essentials/minikql/comp_nodes/ya.make.inc +++ b/yql/essentials/minikql/comp_nodes/ya.make.inc @@ -21,6 +21,7 @@ SET(ORIG_SOURCES mkql_block_getelem.cpp mkql_block_guess.cpp mkql_block_variant.cpp + mkql_block_variant_item.cpp mkql_block_way.cpp mkql_block_if.cpp mkql_block_just.cpp diff --git a/yql/essentials/minikql/mkql_program_builder.cpp b/yql/essentials/minikql/mkql_program_builder.cpp index 87ed9bbbeb7..68c92cda92c 100644 --- a/yql/essentials/minikql/mkql_program_builder.cpp +++ b/yql/essentials/minikql/mkql_program_builder.cpp @@ -6422,6 +6422,24 @@ TRuntimeNode TProgramBuilder::BlockVariant(TRuntimeNode item, const std::string_ return TRuntimeNode(callableBuilder.Build(), /*isImmediate=*/false); } +TRuntimeNode TProgramBuilder::BlockVariantItem(TRuntimeNode variant) { + if constexpr (RuntimeVersion < 82) { + THROW yexception() << "Runtime version (" << RuntimeVersion << ") too old for " << __func__; + } + auto blockType = AS_TYPE(TBlockType, variant.GetStaticType()); + auto inputItemType = blockType->GetItemType(); + bool isOptional; + auto unpacked = UnpackOptional(inputItemType, isOptional); + auto variantType = AS_TYPE(TVariantType, unpacked); + auto alternativeType = variantType->GetAlternativeType(0); + auto itemReturnType = isOptional ? NewOptionalType(alternativeType) : alternativeType; + auto returnType = NewBlockType(itemReturnType, blockType->GetShape()); + + TCallableBuilder callableBuilder(Env_, __func__, returnType); + callableBuilder.Add(variant); + return TRuntimeNode(callableBuilder.Build(), /*isImmediate=*/false); +} + TRuntimeNode TProgramBuilder::BlockIf(TRuntimeNode condition, TRuntimeNode thenBranch, TRuntimeNode elseBranch) { const auto conditionType = AS_TYPE(TBlockType, condition.GetStaticType()); MKQL_ENSURE(AS_TYPE(TDataType, conditionType->GetItemType())->GetSchemeType() == NUdf::TDataType<bool>::Id, diff --git a/yql/essentials/minikql/mkql_program_builder.h b/yql/essentials/minikql/mkql_program_builder.h index 32fccf7c7c8..79369bf401e 100644 --- a/yql/essentials/minikql/mkql_program_builder.h +++ b/yql/essentials/minikql/mkql_program_builder.h @@ -307,6 +307,7 @@ public: TRuntimeNode BlockWay(TRuntimeNode variant); TRuntimeNode BlockVariant(TRuntimeNode item, ui32 tupleIndex, TType* variantType); TRuntimeNode BlockVariant(TRuntimeNode item, const std::string_view& memberName, TType* variantType); + TRuntimeNode BlockVariantItem(TRuntimeNode variant); TRuntimeNode BlockIf(TRuntimeNode condition, TRuntimeNode thenBranch, TRuntimeNode elseBranch); TRuntimeNode BlockJust(TRuntimeNode data); diff --git a/yql/essentials/minikql/mkql_runtime_version.h b/yql/essentials/minikql/mkql_runtime_version.h index c1fec777ada..2f2c454ef19 100644 --- a/yql/essentials/minikql/mkql_runtime_version.h +++ b/yql/essentials/minikql/mkql_runtime_version.h @@ -28,7 +28,7 @@ namespace NKikimr::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 81U + #define MKQL_RUNTIME_VERSION 82U #endif class TRuntimeVersion { diff --git a/yql/essentials/providers/common/mkql/yql_provider_mkql.cpp b/yql/essentials/providers/common/mkql/yql_provider_mkql.cpp index 21b1137e6ef..5761f947da3 100644 --- a/yql/essentials/providers/common/mkql/yql_provider_mkql.cpp +++ b/yql/essentials/providers/common/mkql/yql_provider_mkql.cpp @@ -1023,6 +1023,11 @@ TMkqlCommonCallableCompiler::TShared::TShared() { return ctx.ProgramBuilder.BlockVariant(payloadValue, node.Child(1)->Content(), type); }); + AddCallable("BlockVariantItem", [](const TExprNode& node, TMkqlBuildContext& ctx) { + const auto blockVariantValue = MkqlBuildExpr(*node.Child(0), ctx); + return ctx.ProgramBuilder.BlockVariantItem(blockVariantValue); + }); + AddCallable("Visit", [](const TExprNode& node, TMkqlBuildContext& ctx) { const auto variantObj = MkqlBuildExpr(node.Head(), ctx); const auto type = node.Head().GetTypeAnn()->Cast<TVariantExprType>(); diff --git a/yql/essentials/tests/sql/minirun/part0/canondata/result.json b/yql/essentials/tests/sql/minirun/part0/canondata/result.json index 90221a7ca8b..d8545e051d0 100644 --- a/yql/essentials/tests/sql/minirun/part0/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part0/canondata/result.json @@ -405,6 +405,27 @@ "uri": "https://{canondata_backend}/1937424/d02bb271c9ab67557c669f52bc80a0a698a8a91e/resource.tar.gz#test.test_blocks-if-default.txt-Results_/results.txt" } ], + "test.test[blocks-variant_item_tuple-default.txt-Debug]": [ + { + "checksum": "c51dc11884e895fa059d737ee2c9c045", + "size": 580, + "uri": "https://{canondata_backend}/1946324/b9fe6a5a945e23db9e4ac84e6edac51b4a9a7c92/resource.tar.gz#test.test_blocks-variant_item_tuple-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-variant_item_tuple-default.txt-Peephole]": [ + { + "checksum": "13d96e6fdc5acc50cce29fb454ffcffd", + "size": 744, + "uri": "https://{canondata_backend}/1946324/b9fe6a5a945e23db9e4ac84e6edac51b4a9a7c92/resource.tar.gz#test.test_blocks-variant_item_tuple-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-variant_item_tuple-default.txt-Results]": [ + { + "checksum": "752787be97605457fe04ca12d9a6ce54", + "size": 839, + "uri": "https://{canondata_backend}/1946324/b9fe6a5a945e23db9e4ac84e6edac51b4a9a7c92/resource.tar.gz#test.test_blocks-variant_item_tuple-default.txt-Results_/results.txt" + } + ], "test.test[column_order-values-default.txt-Debug]": [ { "checksum": "ec4c1859bead1f9b88e6239fe8d6addb", diff --git a/yql/essentials/tests/sql/minirun/part13/canondata/result.json b/yql/essentials/tests/sql/minirun/part13/canondata/result.json index 82cf4f95a1c..1a544f54aa2 100644 --- a/yql/essentials/tests/sql/minirun/part13/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part13/canondata/result.json @@ -383,6 +383,27 @@ "uri": "https://{canondata_backend}/1871002/12af85b5b27eccd0e3391513f34ad8082ac84843/resource.tar.gz#test.test_blocks-or-default.txt-Results_/results.txt" } ], + "test.test[blocks-variant_item_tuple_double_optional-default.txt-Debug]": [ + { + "checksum": "6fcb3db2f3daa7aa700968df1e76ba04", + "size": 719, + "uri": "https://{canondata_backend}/1936273/854abe42453705136666cc5b313bfc721a48afea/resource.tar.gz#test.test_blocks-variant_item_tuple_double_optional-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-variant_item_tuple_double_optional-default.txt-Peephole]": [ + { + "checksum": "1b2d155e8eff24e51aae77f266b10790", + "size": 881, + "uri": "https://{canondata_backend}/1936273/854abe42453705136666cc5b313bfc721a48afea/resource.tar.gz#test.test_blocks-variant_item_tuple_double_optional-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-variant_item_tuple_double_optional-default.txt-Results]": [ + { + "checksum": "86ee982d1332b88e012416d3bc5d0a88", + "size": 1614, + "uri": "https://{canondata_backend}/1925821/46269e5add3027e8022118942f0b2ec4a7d413c8/resource.tar.gz#test.test_blocks-variant_item_tuple_double_optional-default.txt-Results_/results.txt" + } + ], "test.test[blocks-xor_scalar-default.txt-Debug]": [ { "checksum": "01875c4a7756e30537fbaa02d4b70d91", diff --git a/yql/essentials/tests/sql/minirun/part15/canondata/result.json b/yql/essentials/tests/sql/minirun/part15/canondata/result.json index fe0b1cd7794..daaf80a7a77 100644 --- a/yql/essentials/tests/sql/minirun/part15/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part15/canondata/result.json @@ -272,6 +272,48 @@ "uri": "https://{canondata_backend}/1777230/1de313d944cae10d4384ec6656e7270944aba259/resource.tar.gz#test.test_blocks-or_opt-default.txt-Results_/results.txt" } ], + "test.test[blocks-variant_item_struct_double_optional-default.txt-Debug]": [ + { + "checksum": "d7ec18fc97a188f3846ea4756e9709ee", + "size": 736, + "uri": "https://{canondata_backend}/1817427/438cafea5ac685cff797d9f5e48093ac686b940d/resource.tar.gz#test.test_blocks-variant_item_struct_double_optional-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-variant_item_struct_double_optional-default.txt-Peephole]": [ + { + "checksum": "a40b5a9d4491f3bddaf50e8e867d293f", + "size": 898, + "uri": "https://{canondata_backend}/1817427/438cafea5ac685cff797d9f5e48093ac686b940d/resource.tar.gz#test.test_blocks-variant_item_struct_double_optional-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-variant_item_struct_double_optional-default.txt-Results]": [ + { + "checksum": "86ee982d1332b88e012416d3bc5d0a88", + "size": 1614, + "uri": "https://{canondata_backend}/1871002/3c6c923fa59fd1bab5a053dabe0a04b0e87dc418/resource.tar.gz#test.test_blocks-variant_item_struct_double_optional-default.txt-Results_/results.txt" + } + ], + "test.test[blocks-variant_item_struct_optional-default.txt-Debug]": [ + { + "checksum": "95682f190c7e476bf8b347aed03248f8", + "size": 569, + "uri": "https://{canondata_backend}/1817427/438cafea5ac685cff797d9f5e48093ac686b940d/resource.tar.gz#test.test_blocks-variant_item_struct_optional-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-variant_item_struct_optional-default.txt-Peephole]": [ + { + "checksum": "b37e9c2fd12bd6e6eeaf588db65e2842", + "size": 729, + "uri": "https://{canondata_backend}/1817427/438cafea5ac685cff797d9f5e48093ac686b940d/resource.tar.gz#test.test_blocks-variant_item_struct_optional-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-variant_item_struct_optional-default.txt-Results]": [ + { + "checksum": "576dc6ba6fccf551cbdb2bd0d9a5ffdd", + "size": 1084, + "uri": "https://{canondata_backend}/1784117/cb5e9e20f085a53076de3c3accaa5636a96c40af/resource.tar.gz#test.test_blocks-variant_item_struct_optional-default.txt-Results_/results.txt" + } + ], "test.test[case-case_opt_cond-default.txt-Debug]": [ { "checksum": "4fd4460b8d2584006fe79cb1cb1e538e", diff --git a/yql/essentials/tests/sql/minirun/part4/canondata/result.json b/yql/essentials/tests/sql/minirun/part4/canondata/result.json index ed55d8d0852..05e92a8724e 100644 --- a/yql/essentials/tests/sql/minirun/part4/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part4/canondata/result.json @@ -412,6 +412,27 @@ "uri": "https://{canondata_backend}/1781765/06cae327ea6c6fc81b5ac8d206f80c5f2f779d8e/resource.tar.gz#test.test_blocks-ifpresent_null_last_argument-default.txt-Results_/results.txt" } ], + "test.test[blocks-variant_item_tuple_optional-default.txt-Debug]": [ + { + "checksum": "62919382fcfc0dd997eead6f4e03a932", + "size": 552, + "uri": "https://{canondata_backend}/1817427/09d302bef9ec38bcb4a935c4b330a4d5cd031a5c/resource.tar.gz#test.test_blocks-variant_item_tuple_optional-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-variant_item_tuple_optional-default.txt-Peephole]": [ + { + "checksum": "c4bdf988655437c82a6bbe85e4455d85", + "size": 712, + "uri": "https://{canondata_backend}/1817427/09d302bef9ec38bcb4a935c4b330a4d5cd031a5c/resource.tar.gz#test.test_blocks-variant_item_tuple_optional-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-variant_item_tuple_optional-default.txt-Results]": [ + { + "checksum": "576dc6ba6fccf551cbdb2bd0d9a5ffdd", + "size": 1084, + "uri": "https://{canondata_backend}/1942278/1f4ac0fbebe543a2fb8b2b163831240b6d36147c/resource.tar.gz#test.test_blocks-variant_item_tuple_optional-default.txt-Results_/results.txt" + } + ], "test.test[blocks-xor_opt_scalar-default.txt-Debug]": [ { "checksum": "27783c2f95862105c305c624babb7dfe", diff --git a/yql/essentials/tests/sql/minirun/part6/canondata/result.json b/yql/essentials/tests/sql/minirun/part6/canondata/result.json index 1639fa9c66f..dabd5d061d9 100644 --- a/yql/essentials/tests/sql/minirun/part6/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part6/canondata/result.json @@ -447,6 +447,27 @@ "uri": "https://{canondata_backend}/1920236/cd7892eb0facff7eb2c6e0b30c741174c37d06f1/resource.tar.gz#test.test_blocks-singular_type_scalar-default.txt-Results_/results.txt" } ], + "test.test[blocks-variant_item_struct-default.txt-Debug]": [ + { + "checksum": "f1779ed08401f8a3cb57b7214d5bf541", + "size": 509, + "uri": "https://{canondata_backend}/1784117/485dcef955bd6d323f9158400aafb28652804f8f/resource.tar.gz#test.test_blocks-variant_item_struct-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-variant_item_struct-default.txt-Peephole]": [ + { + "checksum": "8c6098c7d4d4a759a4ac3d1ebff32b05", + "size": 685, + "uri": "https://{canondata_backend}/1784117/485dcef955bd6d323f9158400aafb28652804f8f/resource.tar.gz#test.test_blocks-variant_item_struct-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-variant_item_struct-default.txt-Results]": [ + { + "checksum": "30d44c52485b3e84ca77e1feace2a4b1", + "size": 765, + "uri": "https://{canondata_backend}/1784117/485dcef955bd6d323f9158400aafb28652804f8f/resource.tar.gz#test.test_blocks-variant_item_struct-default.txt-Results_/results.txt" + } + ], "test.test[blocks-variant_struct-default.txt-Debug]": [ { "checksum": "5b7ccf38526cde333d2b3b92ae8acaba", diff --git a/yql/essentials/tests/sql/sql2yql/canondata/result.json b/yql/essentials/tests/sql/sql2yql/canondata/result.json index c7586d62951..f7b3d04f180 100644 --- a/yql/essentials/tests/sql/sql2yql/canondata/result.json +++ b/yql/essentials/tests/sql/sql2yql/canondata/result.json @@ -2589,6 +2589,48 @@ "uri": "https://{canondata_backend}/1942100/698d95eec1cbd4e4ada1a8da105c203a7a12bb85/resource.tar.gz#test_sql2yql.test_blocks-topg_/sql.yql" } ], + "test_sql2yql.test[blocks-variant_item_struct]": [ + { + "checksum": "5fbb028b27ac5363cf30639b2ac3c772", + "size": 1300, + "uri": "https://{canondata_backend}/1936273/19a7ee3dffd801646a27a6f23176e8cc2837724d/resource.tar.gz#test_sql2yql.test_blocks-variant_item_struct_/sql.yql" + } + ], + "test_sql2yql.test[blocks-variant_item_struct_double_optional]": [ + { + "checksum": "70bfa15e505250659671b7ad9fa45d5a", + "size": 1648, + "uri": "https://{canondata_backend}/1936273/19a7ee3dffd801646a27a6f23176e8cc2837724d/resource.tar.gz#test_sql2yql.test_blocks-variant_item_struct_double_optional_/sql.yql" + } + ], + "test_sql2yql.test[blocks-variant_item_struct_optional]": [ + { + "checksum": "42f0f2748a1554da68958abe6efed009", + "size": 1384, + "uri": "https://{canondata_backend}/1936273/19a7ee3dffd801646a27a6f23176e8cc2837724d/resource.tar.gz#test_sql2yql.test_blocks-variant_item_struct_optional_/sql.yql" + } + ], + "test_sql2yql.test[blocks-variant_item_tuple]": [ + { + "checksum": "7aa768c192d2add04dc4a5fa9076c77f", + "size": 1357, + "uri": "https://{canondata_backend}/1936273/19a7ee3dffd801646a27a6f23176e8cc2837724d/resource.tar.gz#test_sql2yql.test_blocks-variant_item_tuple_/sql.yql" + } + ], + "test_sql2yql.test[blocks-variant_item_tuple_double_optional]": [ + { + "checksum": "fc8655b0759014f8d37956a28910e980", + "size": 1631, + "uri": "https://{canondata_backend}/1936273/19a7ee3dffd801646a27a6f23176e8cc2837724d/resource.tar.gz#test_sql2yql.test_blocks-variant_item_tuple_double_optional_/sql.yql" + } + ], + "test_sql2yql.test[blocks-variant_item_tuple_optional]": [ + { + "checksum": "70f2c2b80c03f8ad0f43bff4bdacad54", + "size": 1367, + "uri": "https://{canondata_backend}/1936273/19a7ee3dffd801646a27a6f23176e8cc2837724d/resource.tar.gz#test_sql2yql.test_blocks-variant_item_tuple_optional_/sql.yql" + } + ], "test_sql2yql.test[blocks-variant_struct]": [ { "checksum": "2ce6349bc3b6a13f53f519351bcd408c", @@ -14512,6 +14554,36 @@ "uri": "file://test_sql_format.test_blocks-topg_/formatted.sql" } ], + "test_sql_format.test[blocks-variant_item_struct]": [ + { + "uri": "file://test_sql_format.test_blocks-variant_item_struct_/formatted.sql" + } + ], + "test_sql_format.test[blocks-variant_item_struct_double_optional]": [ + { + "uri": "file://test_sql_format.test_blocks-variant_item_struct_double_optional_/formatted.sql" + } + ], + "test_sql_format.test[blocks-variant_item_struct_optional]": [ + { + "uri": "file://test_sql_format.test_blocks-variant_item_struct_optional_/formatted.sql" + } + ], + "test_sql_format.test[blocks-variant_item_tuple]": [ + { + "uri": "file://test_sql_format.test_blocks-variant_item_tuple_/formatted.sql" + } + ], + "test_sql_format.test[blocks-variant_item_tuple_double_optional]": [ + { + "uri": "file://test_sql_format.test_blocks-variant_item_tuple_double_optional_/formatted.sql" + } + ], + "test_sql_format.test[blocks-variant_item_tuple_optional]": [ + { + "uri": "file://test_sql_format.test_blocks-variant_item_tuple_optional_/formatted.sql" + } + ], "test_sql_format.test[blocks-variant_struct]": [ { "uri": "file://test_sql_format.test_blocks-variant_struct_/formatted.sql" diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_/formatted.sql new file mode 100644 index 00000000000..5359e1298cf --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_/formatted.sql @@ -0,0 +1,12 @@ +$structVariantType = Variant<a: Int32, b: Int32>; + +$data = [ + <|variantValue: Variant(1, 'a', $structVariantType)|>, + <|variantValue: Variant(2, 'b', $structVariantType)|>, +]; + +SELECT + Yql::VariantItem(variantValue) AS item +FROM + as_table($data) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_double_optional_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_double_optional_/formatted.sql new file mode 100644 index 00000000000..0448dd0b140 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_double_optional_/formatted.sql @@ -0,0 +1,15 @@ +$structVariantType = Variant<a: Optional<Int32>, b: Optional<Int32>>; + +$optionalData = [ + <|variantValue: Just(Variant(Just(1), 'a', $structVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), 'a', $structVariantType))|>, + <|variantValue: Nothing(OptionalType($structVariantType))|>, + <|variantValue: Just(Variant(Just(2), 'b', $structVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), 'b', $structVariantType))|>, +]; + +SELECT + Yql::VariantItem(variantValue) AS item +FROM + as_table($optionalData) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_optional_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_optional_/formatted.sql new file mode 100644 index 00000000000..c360d4712ec --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_struct_optional_/formatted.sql @@ -0,0 +1,13 @@ +$structVariantType = Variant<a: Int32, b: Int32>; + +$optionalData = [ + <|variantValue: Just(Variant(1, 'a', $structVariantType))|>, + <|variantValue: Nothing(OptionalType($structVariantType))|>, + <|variantValue: Just(Variant(2, 'b', $structVariantType))|>, +]; + +SELECT + Yql::VariantItem(variantValue) AS item +FROM + as_table($optionalData) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_/formatted.sql new file mode 100644 index 00000000000..333807f89be --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_/formatted.sql @@ -0,0 +1,13 @@ +$tupleVariantType = Variant<Int32, Int32>; + +$data = [ + <|variantValue: Variant(1, '0', $tupleVariantType)|>, + <|variantValue: Variant(2, '1', $tupleVariantType)|>, + <|variantValue: Variant(42, '0', $tupleVariantType)|>, +]; + +SELECT + Yql::VariantItem(variantValue) AS item +FROM + as_table($data) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_double_optional_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_double_optional_/formatted.sql new file mode 100644 index 00000000000..5f8d93539d9 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_double_optional_/formatted.sql @@ -0,0 +1,15 @@ +$tupleVariantType = Variant<Optional<Int32>, Optional<Int32>>; + +$optionalData = [ + <|variantValue: Just(Variant(Just(1), '0', $tupleVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), '0', $tupleVariantType))|>, + <|variantValue: Nothing(OptionalType($tupleVariantType))|>, + <|variantValue: Just(Variant(Just(2), '1', $tupleVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), '1', $tupleVariantType))|>, +]; + +SELECT + Yql::VariantItem(variantValue) AS item +FROM + as_table($optionalData) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_optional_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_optional_/formatted.sql new file mode 100644 index 00000000000..259ec274289 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-variant_item_tuple_optional_/formatted.sql @@ -0,0 +1,13 @@ +$tupleVariantType = Variant<Int32, Int32>; + +$optionalData = [ + <|variantValue: Just(Variant(1, '0', $tupleVariantType))|>, + <|variantValue: Nothing(OptionalType($tupleVariantType))|>, + <|variantValue: Just(Variant(2, '1', $tupleVariantType))|>, +]; + +SELECT + Yql::VariantItem(variantValue) AS item +FROM + as_table($optionalData) +; diff --git a/yql/essentials/tests/sql/suites/blocks/variant_item_struct.yql b/yql/essentials/tests/sql/suites/blocks/variant_item_struct.yql new file mode 100644 index 00000000000..b825c0c4fec --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/variant_item_struct.yql @@ -0,0 +1,8 @@ +$structVariantType = Variant<a: Int32, b: Int32>; + +$data = [ + <|variantValue: Variant(1, "a", $structVariantType)|>, + <|variantValue: Variant(2, "b", $structVariantType)|>, +]; + +SELECT Yql::VariantItem(variantValue) AS item FROM as_table($data); diff --git a/yql/essentials/tests/sql/suites/blocks/variant_item_struct_double_optional.yql b/yql/essentials/tests/sql/suites/blocks/variant_item_struct_double_optional.yql new file mode 100644 index 00000000000..a81ffba680f --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/variant_item_struct_double_optional.yql @@ -0,0 +1,11 @@ +$structVariantType = Variant<a: Optional<Int32>, b: Optional<Int32>>; + +$optionalData = [ + <|variantValue: Just(Variant(Just(1), "a", $structVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), "a", $structVariantType))|>, + <|variantValue: Nothing(OptionalType($structVariantType))|>, + <|variantValue: Just(Variant(Just(2), "b", $structVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), "b", $structVariantType))|>, +]; + +SELECT Yql::VariantItem(variantValue) AS item FROM as_table($optionalData); diff --git a/yql/essentials/tests/sql/suites/blocks/variant_item_struct_optional.yql b/yql/essentials/tests/sql/suites/blocks/variant_item_struct_optional.yql new file mode 100644 index 00000000000..53a3dfe9a13 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/variant_item_struct_optional.yql @@ -0,0 +1,9 @@ +$structVariantType = Variant<a: Int32, b: Int32>; + +$optionalData = [ + <|variantValue: Just(Variant(1, "a", $structVariantType))|>, + <|variantValue: Nothing(OptionalType($structVariantType))|>, + <|variantValue: Just(Variant(2, "b", $structVariantType))|>, +]; + +SELECT Yql::VariantItem(variantValue) AS item FROM as_table($optionalData); diff --git a/yql/essentials/tests/sql/suites/blocks/variant_item_tuple.yql b/yql/essentials/tests/sql/suites/blocks/variant_item_tuple.yql new file mode 100644 index 00000000000..f1fc295d091 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/variant_item_tuple.yql @@ -0,0 +1,9 @@ +$tupleVariantType = Variant<Int32, Int32>; + +$data = [ + <|variantValue: Variant(1, "0", $tupleVariantType)|>, + <|variantValue: Variant(2, "1", $tupleVariantType)|>, + <|variantValue: Variant(42, "0", $tupleVariantType)|>, +]; + +SELECT Yql::VariantItem(variantValue) AS item FROM as_table($data); diff --git a/yql/essentials/tests/sql/suites/blocks/variant_item_tuple_double_optional.yql b/yql/essentials/tests/sql/suites/blocks/variant_item_tuple_double_optional.yql new file mode 100644 index 00000000000..324230dd5b0 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/variant_item_tuple_double_optional.yql @@ -0,0 +1,11 @@ +$tupleVariantType = Variant<Optional<Int32>, Optional<Int32>>; + +$optionalData = [ + <|variantValue: Just(Variant(Just(1), "0", $tupleVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), "0", $tupleVariantType))|>, + <|variantValue: Nothing(OptionalType($tupleVariantType))|>, + <|variantValue: Just(Variant(Just(2), "1", $tupleVariantType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), "1", $tupleVariantType))|>, +]; + +SELECT Yql::VariantItem(variantValue) AS item FROM as_table($optionalData); diff --git a/yql/essentials/tests/sql/suites/blocks/variant_item_tuple_optional.yql b/yql/essentials/tests/sql/suites/blocks/variant_item_tuple_optional.yql new file mode 100644 index 00000000000..bc9aefe9752 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/variant_item_tuple_optional.yql @@ -0,0 +1,9 @@ +$tupleVariantType = Variant<Int32, Int32>; + +$optionalData = [ + <|variantValue: Just(Variant(1, "0", $tupleVariantType))|>, + <|variantValue: Nothing(OptionalType($tupleVariantType))|>, + <|variantValue: Just(Variant(2, "1", $tupleVariantType))|>, +]; + +SELECT Yql::VariantItem(variantValue) AS item FROM as_table($optionalData); |
