diff options
29 files changed, 772 insertions, 2 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 1edff421068..1e935d1912d 100644 --- a/yql/essentials/core/peephole_opt/yql_opt_peephole_physical.cpp +++ b/yql/essentials/core/peephole_opt/yql_opt_peephole_physical.cpp @@ -6450,7 +6450,8 @@ private: TExprNode::TListType funcArgs; std::string_view arrowFunctionName; const bool rewriteAsIs = node->IsCallable({"AssumeStrict", "AssumeNonStrict", "NoPush", "Likely"}); - if (node->IsList() || rewriteAsIs || + bool isSuitableGuess = NKikimr::NMiniKQL::RuntimeVersion >= 79 && node->IsCallable("Guess"); + if (node->IsList() || rewriteAsIs || isSuitableGuess || 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_, 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 64bab47ae2d..34094b449f3 100644 --- a/yql/essentials/core/type_ann/type_ann_blocks.cpp +++ b/yql/essentials/core/type_ann/type_ann_blocks.cpp @@ -352,6 +352,61 @@ IGraphTransformer::TStatus BlockDecimalBinaryWrapper(const TExprNode::TPtr& inpu return DecimalBinaryWrapperBase(input, output, ctx, /*blocks=*/ true); } +IGraphTransformer::TStatus BlockGuessWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) { + Y_UNUSED(output); + if (!EnsureArgsCount(*input, 2, 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); + + const TTypeAnnotationNode* innerItemType = itemType; + if (innerItemType->GetKind() == ETypeAnnotationKind::Optional) { + innerItemType = innerItemType->Cast<TOptionalExprType>()->GetItemType(); + } + if (!EnsureVariantType(variantNode->Pos(), *innerItemType, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + auto variantType = innerItemType->Cast<TVariantExprType>(); + + if (!EnsureAtom(*input->Child(1), ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + const TTypeAnnotationNode* alternativeType = nullptr; + if (variantType->GetUnderlyingType()->GetKind() == ETypeAnnotationKind::Tuple) { + auto tupleType = variantType->GetUnderlyingType()->Cast<TTupleExprType>(); + ui32 index = 0; + if (!TryFromString(input->Child(1)->Content(), index)) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(input->Pos()), + TStringBuilder() << "Failed to convert to integer: " << input->Child(1)->Content())); + return IGraphTransformer::TStatus::Error; + } + if (index >= tupleType->GetSize()) { + ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(input->Pos()), + TStringBuilder() << "Index out of range. Index: " << index << ", size: " << tupleType->GetSize())); + return IGraphTransformer::TStatus::Error; + } + alternativeType = tupleType->GetItems()[index]; + } else { + auto structType = variantType->GetUnderlyingType()->Cast<TStructExprType>(); + auto pos = FindOrReportMissingMember(input->Child(1)->Content(), input->Pos(), *structType, ctx.Expr); + if (!pos) { + return IGraphTransformer::TStatus::Error; + } + alternativeType = structType->GetItems()[*pos]->GetItemType(); + } + + auto optionalAlternativeType = ctx.Expr.MakeType<TOptionalExprType>(alternativeType); + input->SetTypeAnn(MakeBlockOrScalarType(optionalAlternativeType, 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 6050893b73c..4fdaad8f1ec 100644 --- a/yql/essentials/core/type_ann/type_ann_blocks.h +++ b/yql/essentials/core/type_ann/type_ann_blocks.h @@ -16,6 +16,7 @@ namespace NYql::NTypeAnnImpl { IGraphTransformer::TStatus BlockValidUnwrapWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockCoalesceWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus BlockLogicalWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); + IGraphTransformer::TStatus BlockGuessWrapper(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 1b8c731d814..d95673e3979 100644 --- a/yql/essentials/core/type_ann/type_ann_core.cpp +++ b/yql/essentials/core/type_ann/type_ann_core.cpp @@ -16460,6 +16460,7 @@ template <NKikimr::NUdf::EDataSlot DataSlot> Functions["BlockOr"] = &BlockLogicalWrapper; Functions["BlockXor"] = &BlockLogicalWrapper; Functions["BlockNot"] = &BlockLogicalWrapper; + Functions["BlockGuess"] = &BlockGuessWrapper; Functions["BlockIf"] = &BlockIfWrapper; Functions["BlockJust"] = &BlockJustWrapper; Functions["BlockAsStruct"] = &BlockAsStructWrapper; diff --git a/yql/essentials/minikql/comp_nodes/mkql_block_guess.cpp b/yql/essentials/minikql/comp_nodes/mkql_block_guess.cpp new file mode 100644 index 00000000000..d13e839f5c0 --- /dev/null +++ b/yql/essentials/minikql/comp_nodes/mkql_block_guess.cpp @@ -0,0 +1,134 @@ +#include "mkql_block_guess.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 { +namespace NMiniKQL { + +namespace { + +template <bool IsOptional> +class TGuessBlockExec { +public: + class TGuessKernelState: public arrow::compute::KernelState { + public: + explicit TGuessKernelState(TType* inputItemType) + : Reader_(MakeBlockReader(TTypeInfoHelper(), inputItemType)) + { + } + + IBlockReader& GetReader() { + return *Reader_; + } + + private: + std::unique_ptr<IBlockReader> Reader_; + }; + + explicit TGuessBlockExec(TType* inputItemType, ui32 alternativeIndex, TType* resultItemType) + : InputItemType_(inputItemType) + , AlternativeIndex_(alternativeIndex) + , ResultItemType_(resultItemType) + { + } + + arrow::Status Exec(arrow::compute::KernelContext* ctx, const arrow::compute::ExecBatch& batch, arrow::Datum* res) const { + auto& reader = static_cast<TGuessKernelState&>(*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.GetVariantIndex() == AlternativeIndex_ + ? blockItem.GetVariantItem().MakeOptional() + : TBlockItem{}; + } + + TType* const InputItemType_; + const ui32 AlternativeIndex_; + TType* const ResultItemType_; +}; + +template <bool IsOptional> +std::shared_ptr<arrow::compute::ScalarKernel> MakeBlockGuessKernel(const TVector<TType*>& argTypes, + TType* resultType, + TType* inputItemType, + ui32 alternativeIndex) { + using TExec = TGuessBlockExec<IsOptional>; + auto exec = std::make_shared<TExec>( + inputItemType, + alternativeIndex, + 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::TGuessKernelState>(inputItemType)); + }; + return kernel; +} + +} // namespace + +IComputationNode* WrapBlockGuess(TCallable& callable, const TComputationNodeFactoryContext& ctx) { + MKQL_ENSURE(callable.GetInputsCount() == 2, "Expected 2 arguments"); + + auto blockType = AS_TYPE(TBlockType, callable.GetInput(0).GetStaticType()); + auto inputItemType = blockType->GetItemType(); + + bool isOptional; + auto variantItemType = UnpackOptional(inputItemType, isOptional); + auto variantType = AS_TYPE(TVariantType, variantItemType); + + const ui32 alternativeIndex = AS_VALUE(TDataLiteral, callable.GetInput(1))->AsValue().Get<ui32>(); + MKQL_ENSURE(alternativeIndex < variantType->GetAlternativesCount(), "Bad alternative index"); + + auto variantCompute = LocateNode(ctx.NodeLocator, callable, 0); + TComputationNodePtrVector argsNodes = {variantCompute}; + TVector<TType*> argsTypes = {blockType}; + + auto resultType = callable.GetType()->GetReturnType(); + + auto kernel = isOptional + ? MakeBlockGuessKernel<true>(argsTypes, resultType, inputItemType, alternativeIndex) + : MakeBlockGuessKernel<false>(argsTypes, resultType, inputItemType, alternativeIndex); + + return new TBlockFuncNode(ctx.Mutables, ctx.RuntimeSettings->DatumValidation.Get(), + callable.GetType()->GetName(), std::move(argsNodes), argsTypes, resultType, *kernel, kernel); +} + +} // namespace NMiniKQL +} // namespace NKikimr diff --git a/yql/essentials/minikql/comp_nodes/mkql_block_guess.h b/yql/essentials/minikql/comp_nodes/mkql_block_guess.h new file mode 100644 index 00000000000..124929ecd51 --- /dev/null +++ b/yql/essentials/minikql/comp_nodes/mkql_block_guess.h @@ -0,0 +1,10 @@ +#pragma once +#include <yql/essentials/minikql/computation/mkql_computation_node.h> + +namespace NKikimr { +namespace NMiniKQL { + +IComputationNode* WrapBlockGuess(TCallable& callable, const TComputationNodeFactoryContext& ctx); + +} // namespace NMiniKQL +} // namespace NKikimr diff --git a/yql/essentials/minikql/comp_nodes/mkql_factory.cpp b/yql/essentials/minikql/comp_nodes/mkql_factory.cpp index ce7637b32d8..75faa470c6c 100644 --- a/yql/essentials/minikql/comp_nodes/mkql_factory.cpp +++ b/yql/essentials/minikql/comp_nodes/mkql_factory.cpp @@ -12,6 +12,7 @@ #include "mkql_block_decimal.h" #include "mkql_block_exists.h" #include "mkql_block_getelem.h" +#include "mkql_block_guess.h" #include "mkql_block_if.h" #include "mkql_block_just.h" #include "mkql_block_logical.h" @@ -308,6 +309,7 @@ struct TCallableComputationNodeBuilderFuncMapFiller { {"ReplicateScalar", &WrapReplicateScalar}, {"BlockCoalesce", &WrapBlockCoalesce}, {"BlockExists", &WrapBlockExists}, + {"BlockGuess", &WrapBlockGuess}, {"BlockIf", &WrapBlockIf}, {"BlockAnd", &WrapBlockAnd}, {"BlockOr", &WrapBlockOr}, diff --git a/yql/essentials/minikql/comp_nodes/ut/mkql_block_guess_ut.cpp b/yql/essentials/minikql/comp_nodes/ut/mkql_block_guess_ut.cpp new file mode 100644 index 00000000000..e90dfbe8869 --- /dev/null +++ b/yql/essentials/minikql/comp_nodes/ut/mkql_block_guess_ut.cpp @@ -0,0 +1,226 @@ +#include <yql/essentials/minikql/comp_nodes/mkql_block_guess.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> + +namespace NKikimr::NMiniKQL { + +using namespace NTest; + +namespace { + +template <typename TInputData, typename TExpectedData> +void TestBlockGuess(const TVector<TInputData>& data, const TVector<TExpectedData>& expected, ui32 tupleIndex) { + TBlockHelper().TestKernelFuzzied(data, expected, [tupleIndex](TSetup<false>& setup, TRuntimeNode variantValue) { + return setup.PgmBuilder->BlockGuess(variantValue, tupleIndex); + }); +} + +} // namespace + +Y_UNIT_TEST_SUITE(TMiniKQLBlockGuessTest) { + +Y_UNIT_TEST(TupleVariant_Ui32Ui64_Index0) { + using TVariant = std::variant<ui32, ui64>; + TVector<TVariant> data = {TVariant{ui32{1}}, TVariant{ui64{2}}, TVariant{ui32{3}}}; + TVector<TMaybe<ui32>> expected = {ui32{1}, Nothing(), ui32{3}}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_Ui32Ui64_Index1) { + using TVariant = std::variant<ui32, ui64>; + TVector<TVariant> data = {TVariant{ui32{1}}, TVariant{ui64{2}}, TVariant{ui32{3}}}; + TVector<TMaybe<ui64>> expected = {Nothing(), ui64{2}, Nothing()}; + TestBlockGuess(data, expected, 1u); +} + +Y_UNIT_TEST(TupleVariant_AllSameAlternative) { + using TVariant = std::variant<ui32, ui64>; + TVector<TVariant> data = {TVariant{ui32{10}}, TVariant{ui32{20}}, TVariant{ui32{30}}}; + TVector<TMaybe<ui32>> expected = {ui32{10}, ui32{20}, ui32{30}}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_NoneMatchAlternative) { + using TVariant = std::variant<ui32, ui64>; + TVector<TVariant> data = {TVariant{ui32{1}}, TVariant{ui32{2}}, TVariant{ui32{3}}}; + TVector<TMaybe<ui64>> expected = {Nothing(), Nothing(), Nothing()}; + TestBlockGuess(data, expected, 1u); +} + +Y_UNIT_TEST(TupleVariant_StringAlternative) { + using TVariant = std::variant<ui32, TString>; + TVector<TVariant> data = {TVariant{ui32{42}}, TVariant{TString{"hello"}}, TVariant{ui32{7}}}; + TVector<TMaybe<TString>> expected = {Nothing(), TMaybe<TString>{"hello"}, Nothing()}; + TestBlockGuess(data, expected, 1u); +} + +Y_UNIT_TEST(TupleVariant_TupleAlternative) { + using TTupleAlternative = std::tuple<ui32, TString>; + using TVariant = std::variant<TTupleAlternative, ui64>; + TVector<TVariant> data = { + TVariant{TTupleAlternative{ui32{1}, TString{"a"}}}, + TVariant{ui64{2}}, + TVariant{TTupleAlternative{ui32{3}, TString{"b"}}}, + }; + TVector<TMaybe<TTupleAlternative>> expected = { + TMaybe<TTupleAlternative>{TTupleAlternative{ui32{1}, TString{"a"}}}, + Nothing(), + TMaybe<TTupleAlternative>{TTupleAlternative{ui32{3}, TString{"b"}}}, + }; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_PgIntAlternative) { + using TVariant = std::variant<TPgInt, ui64>; + TVector<TVariant> data = {TVariant{TPgInt{10}}, TVariant{ui64{20}}, TVariant{TPgInt{30}}}; + TVector<TMaybe<TPgInt>> expected = {TMaybe<TPgInt>{TPgInt{10}}, Nothing(), TMaybe<TPgInt>{TPgInt{30}}}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_OptionalAlternative_DoubleOptional) { + using TVariant = std::variant<TMaybe<ui32>, ui64>; + TVector<TVariant> data = { + TVariant{TMaybe<ui32>{10u}}, + TVariant{ui64{20u}}, + TVariant{TMaybe<ui32>{}}, + }; + TVector<TMaybe<TMaybe<ui32>>> expected = { + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{10u}}, + TMaybe<TMaybe<ui32>>{}, + TMaybe<TMaybe<ui32>>{TMaybe<ui32>{}}, + }; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(OptionalTupleVariant_NullRows) { + using TVariant = std::variant<ui32, ui64>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{ui32{1}}}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant{ui32{3}}}, + }; + TVector<TMaybe<ui32>> expected = {ui32{1}, Nothing(), ui32{3}}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(OptionalTupleVariant_AllNull) { + using TVariant = std::variant<ui32, ui64>; + TVector<TMaybe<TVariant>> data = {TMaybe<TVariant>{}, TMaybe<TVariant>{}, TMaybe<TVariant>{}}; + TVector<TMaybe<ui32>> expected = {Nothing(), Nothing(), Nothing()}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(OptionalTupleVariant_NoNull) { + using TVariant = std::variant<ui32, ui64>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{ui32{1}}}, + TMaybe<TVariant>{TVariant{ui64{2}}}, + TMaybe<TVariant>{TVariant{ui32{3}}}, + }; + TVector<TMaybe<ui32>> expected = {ui32{1}, Nothing(), ui32{3}}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(OptionalTupleVariant_MixedNull) { + using TVariant = std::variant<ui32, ui64>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{ui64{10}}}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant{ui64{20}}}, + }; + TVector<TMaybe<ui64>> expected = {ui64{10}, Nothing(), ui64{20}}; + TestBlockGuess(data, expected, 1u); +} + +Y_UNIT_TEST(OptionalTupleVariant_SomeFieldsSet_StringAlternative) { + using TVariant = std::variant<TString, ui64>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{TString{"hello"}}}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{TVariant{ui64{42}}}, + TMaybe<TVariant>{TVariant{TString{"world"}}}, + }; + TVector<TMaybe<TString>> expected = { + TMaybe<TString>{"hello"}, + Nothing(), + Nothing(), + TMaybe<TString>{"world"}, + }; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(OptionalTupleVariant_AllFieldsSet_StringAlternative) { + using TVariant = std::variant<TString, ui64>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{TVariant{TString{"foo"}}}, + TMaybe<TVariant>{TVariant{TString{"bar"}}}, + TMaybe<TVariant>{TVariant{TString{"baz"}}}, + }; + TVector<TMaybe<TString>> expected = { + TMaybe<TString>{"foo"}, + TMaybe<TString>{"bar"}, + TMaybe<TString>{"baz"}, + }; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_OptionalString_AllStringsSet) { + using TVariant = std::variant<TMaybe<TString>, ui64>; + TVector<TVariant> data = { + TVariant{TMaybe<TString>{"foo"}}, + TVariant{TMaybe<TString>{"bar"}}, + TVariant{TMaybe<TString>{"baz"}}, + }; + TVector<TMaybe<TMaybe<TString>>> expected = { + TMaybe<TMaybe<TString>>{TMaybe<TString>{"foo"}}, + TMaybe<TMaybe<TString>>{TMaybe<TString>{"bar"}}, + TMaybe<TMaybe<TString>>{TMaybe<TString>{"baz"}}, + }; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_OptionalDouble_AllDoublesSet) { + using TVariant = std::variant<TMaybe<double>, ui64>; + TVector<TVariant> data = { + TVariant{TMaybe<double>{1.5}}, + TVariant{TMaybe<double>{2.5}}, + TVariant{TMaybe<double>{3.5}}, + }; + TVector<TMaybe<TMaybe<double>>> expected = { + TMaybe<TMaybe<double>>{TMaybe<double>{1.5}}, + TMaybe<TMaybe<double>>{TMaybe<double>{2.5}}, + TMaybe<TMaybe<double>>{TMaybe<double>{3.5}}, + }; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(OptionalTupleVariant_AllVariantsOmitted_StringAlternative) { + using TVariant = std::variant<TString, ui64>; + TVector<TMaybe<TVariant>> data = { + TMaybe<TVariant>{}, + TMaybe<TVariant>{}, + TMaybe<TVariant>{}, + }; + TVector<TMaybe<TString>> expected = {Nothing(), Nothing(), Nothing()}; + TestBlockGuess(data, expected, 0u); +} + +Y_UNIT_TEST(TupleVariant_OptionalString_AllStringsOmitted) { + using TVariant = std::variant<TMaybe<TString>, ui64>; + TVector<TVariant> data = { + TVariant{TMaybe<TString>{}}, + TVariant{TMaybe<TString>{}}, + TVariant{TMaybe<TString>{}}, + }; + TVector<TMaybe<TMaybe<TString>>> expected = { + TMaybe<TMaybe<TString>>{TMaybe<TString>{}}, + TMaybe<TMaybe<TString>>{TMaybe<TString>{}}, + TMaybe<TMaybe<TString>>{TMaybe<TString>{}}, + }; + TestBlockGuess(data, expected, 0u); +} + +} // Y_UNIT_TEST_SUITE(TMiniKQLBlockGuessTest) + +} // namespace NKikimr::NMiniKQL diff --git a/yql/essentials/minikql/comp_nodes/ut/ya.make.inc b/yql/essentials/minikql/comp_nodes/ut/ya.make.inc index 642b0afcdb6..bed3bd8f9e9 100644 --- a/yql/essentials/minikql/comp_nodes/ut/ya.make.inc +++ b/yql/essentials/minikql/comp_nodes/ut/ya.make.inc @@ -35,6 +35,7 @@ SET(ORIG_SOURCES mkql_block_test_helper.cpp mkql_block_fuzzer.cpp mkql_block_getelem_ut.cpp + mkql_block_guess_ut.cpp mkql_block_just_ut.cpp mkql_block_top_sort_ut.cpp mkql_block_variant_ut.cpp diff --git a/yql/essentials/minikql/comp_nodes/ya.make.inc b/yql/essentials/minikql/comp_nodes/ya.make.inc index e26c8420d2a..50b7ba84f2e 100644 --- a/yql/essentials/minikql/comp_nodes/ya.make.inc +++ b/yql/essentials/minikql/comp_nodes/ya.make.inc @@ -19,6 +19,7 @@ SET(ORIG_SOURCES mkql_block_decimal.cpp mkql_block_exists.cpp mkql_block_getelem.cpp + mkql_block_guess.cpp mkql_block_if.cpp mkql_block_just.cpp mkql_block_logical.cpp diff --git a/yql/essentials/minikql/mkql_program_builder.cpp b/yql/essentials/minikql/mkql_program_builder.cpp index 47cd5be577e..4f3bb43b487 100644 --- a/yql/essentials/minikql/mkql_program_builder.cpp +++ b/yql/essentials/minikql/mkql_program_builder.cpp @@ -6292,6 +6292,46 @@ TRuntimeNode TProgramBuilder::PgInternal0(TType* returnType) { return TRuntimeNode(callableBuilder.Build(), false); } +TRuntimeNode TProgramBuilder::BlockGuess(TRuntimeNode variant, ui32 tupleIndex) { + if constexpr (RuntimeVersion < 79) { + 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 underlying = AS_TYPE(TTupleType, variantType->GetUnderlyingType()); + MKQL_ENSURE(tupleIndex < underlying->GetElementsCount(), "Wrong tuple index"); + auto alternativeType = underlying->GetElementType(tupleIndex); + auto returnType = NewBlockType(NewOptionalType(alternativeType), blockType->GetShape()); + + TCallableBuilder callableBuilder(Env_, __func__, returnType); + callableBuilder.Add(variant); + callableBuilder.Add(NewDataLiteral<ui32>(tupleIndex)); + return TRuntimeNode(callableBuilder.Build(), false); +} + +TRuntimeNode TProgramBuilder::BlockGuess(TRuntimeNode variant, const std::string_view& memberName) { + if constexpr (RuntimeVersion < 79) { + 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 underlying = AS_TYPE(TStructType, variantType->GetUnderlyingType()); + auto structIndex = underlying->GetMemberIndex(memberName); + auto alternativeType = underlying->GetMemberType(structIndex); + auto returnType = NewBlockType(NewOptionalType(alternativeType), blockType->GetShape()); + + TCallableBuilder callableBuilder(Env_, __func__, returnType); + callableBuilder.Add(variant); + callableBuilder.Add(NewDataLiteral<ui32>(structIndex)); + return TRuntimeNode(callableBuilder.Build(), 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 b6372693cf7..569bc0fe06c 100644 --- a/yql/essentials/minikql/mkql_program_builder.h +++ b/yql/essentials/minikql/mkql_program_builder.h @@ -302,6 +302,8 @@ public: TRuntimeNode BlockOr(TRuntimeNode first, TRuntimeNode second); TRuntimeNode BlockXor(TRuntimeNode first, TRuntimeNode second); + TRuntimeNode BlockGuess(TRuntimeNode variant, ui32 tupleIndex); + TRuntimeNode BlockGuess(TRuntimeNode variant, const std::string_view& memberName); 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 590cba7b6cb..4addfc8a820 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 78U + #define MKQL_RUNTIME_VERSION 79U #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 f1ecb973506..c302604faf4 100644 --- a/yql/essentials/providers/common/mkql/yql_provider_mkql.cpp +++ b/yql/essentials/providers/common/mkql/yql_provider_mkql.cpp @@ -990,6 +990,21 @@ TMkqlCommonCallableCompiler::TShared::TShared() { } }); + AddCallable("BlockGuess", [](const TExprNode& node, TMkqlBuildContext& ctx) { + const auto blockVariantValue = MkqlBuildExpr(*node.Child(0), ctx); + bool isScalar; + const TTypeAnnotationNode* blockItemType = GetBlockItemType(*node.Child(0)->GetTypeAnn(), isScalar); + const TTypeAnnotationNode* variantItemType = blockItemType->GetKind() == ETypeAnnotationKind::Optional + ? blockItemType->Cast<TOptionalExprType>()->GetItemType() + : blockItemType; + const auto* variantType = variantItemType->Cast<TVariantExprType>(); + if (variantType->GetUnderlyingType()->GetKind() == ETypeAnnotationKind::Tuple) { + const auto alternativeIndex = FromString<ui32>(node.Child(1)->Content()); + return ctx.ProgramBuilder.BlockGuess(blockVariantValue, alternativeIndex); + } + return ctx.ProgramBuilder.BlockGuess(blockVariantValue, node.Child(1)->Content()); + }); + 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/part2/canondata/result.json b/yql/essentials/tests/sql/minirun/part2/canondata/result.json index 9d71b171b1f..1a20928220f 100644 --- a/yql/essentials/tests/sql/minirun/part2/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part2/canondata/result.json @@ -212,6 +212,27 @@ "uri": "https://{canondata_backend}/1937150/e249b7faff24c68591c4c61cf9ecf7e069660ddc/resource.tar.gz#test.test_blocks-coalesce_pg_types-default.txt-Results_/results.txt" } ], + "test.test[blocks-guess_tuple_optional-default.txt-Debug]": [ + { + "checksum": "019652f450b6e2938d893a1bf3b5a068", + "size": 673, + "uri": "https://{canondata_backend}/1937429/4b1f75db514670d5b5e84a8a90fff94480086825/resource.tar.gz#test.test_blocks-guess_tuple_optional-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-guess_tuple_optional-default.txt-Peephole]": [ + { + "checksum": "caa828e834e5c7ebfb1f9c981d65153a", + "size": 798, + "uri": "https://{canondata_backend}/1937429/4b1f75db514670d5b5e84a8a90fff94480086825/resource.tar.gz#test.test_blocks-guess_tuple_optional-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-guess_tuple_optional-default.txt-Results]": [ + { + "checksum": "6c183c541d7d1675dec1a471edc070c5", + "size": 1587, + "uri": "https://{canondata_backend}/1937429/4b1f75db514670d5b5e84a8a90fff94480086825/resource.tar.gz#test.test_blocks-guess_tuple_optional-default.txt-Results_/results.txt" + } + ], "test.test[blocks-sort-default.txt-Debug]": [ { "checksum": "f5d0c3ad8b655c3a6684a13ff19885e6", diff --git a/yql/essentials/tests/sql/minirun/part5/canondata/result.json b/yql/essentials/tests/sql/minirun/part5/canondata/result.json index 17daba1efad..59611798116 100644 --- a/yql/essentials/tests/sql/minirun/part5/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part5/canondata/result.json @@ -251,6 +251,27 @@ "uri": "https://{canondata_backend}/1881367/57bfc4a1435f10934d7710509072254b7f260723/resource.tar.gz#test.test_bigdate-compare_big_small-default.txt-Results_/results.txt" } ], + "test.test[blocks-guess_struct_optional_member-default.txt-Debug]": [ + { + "checksum": "e3a46fdda791183fc7d8dcec71eca1b6", + "size": 785, + "uri": "https://{canondata_backend}/1925821/60da0c39c5d2a728756bea3b0baa9e7db3d4268e/resource.tar.gz#test.test_blocks-guess_struct_optional_member-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-guess_struct_optional_member-default.txt-Peephole]": [ + { + "checksum": "377957b7502936a51a97d6112bda318e", + "size": 912, + "uri": "https://{canondata_backend}/1925821/60da0c39c5d2a728756bea3b0baa9e7db3d4268e/resource.tar.gz#test.test_blocks-guess_struct_optional_member-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-guess_struct_optional_member-default.txt-Results]": [ + { + "checksum": "e1ffea58b75a78a03c7d9862ee39dc8d", + "size": 1950, + "uri": "https://{canondata_backend}/1925821/60da0c39c5d2a728756bea3b0baa9e7db3d4268e/resource.tar.gz#test.test_blocks-guess_struct_optional_member-default.txt-Results_/results.txt" + } + ], "test.test[blocks-just-default.txt-Debug]": [ { "checksum": "248412653c63c6892f76b6ed3c91a2ae", diff --git a/yql/essentials/tests/sql/minirun/part6/canondata/result.json b/yql/essentials/tests/sql/minirun/part6/canondata/result.json index 022d99e40c0..2852aec51f8 100644 --- a/yql/essentials/tests/sql/minirun/part6/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part6/canondata/result.json @@ -300,6 +300,27 @@ "uri": "https://{canondata_backend}/1917492/53531106e44e755ea77008ec27c01bc41d81b31c/resource.tar.gz#test.test_blocks-agg_singular_type_value_optional-default.txt-Results_/results.txt" } ], + "test.test[blocks-guess_tuple-default.txt-Debug]": [ + { + "checksum": "b3484c97deecd85485035f71becb6ed3", + "size": 702, + "uri": "https://{canondata_backend}/1889210/a52c86a2a53b24445efdf84bb4f5f2e22189f80b/resource.tar.gz#test.test_blocks-guess_tuple-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-guess_tuple-default.txt-Peephole]": [ + { + "checksum": "fb9a56b5f63ceeae3437f0c5eb32c5ce", + "size": 831, + "uri": "https://{canondata_backend}/1889210/a52c86a2a53b24445efdf84bb4f5f2e22189f80b/resource.tar.gz#test.test_blocks-guess_tuple-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-guess_tuple-default.txt-Results]": [ + { + "checksum": "57b4a9b2ade4fa471979336dc2f30bbf", + "size": 1646, + "uri": "https://{canondata_backend}/1889210/a52c86a2a53b24445efdf84bb4f5f2e22189f80b/resource.tar.gz#test.test_blocks-guess_tuple-default.txt-Results_/results.txt" + } + ], "test.test[blocks-ifpresent_nonstrict-default.txt-Debug]": [ { "checksum": "3408c8b5f15c5ad2bf6d3b498eaee9aa", diff --git a/yql/essentials/tests/sql/minirun/part7/canondata/result.json b/yql/essentials/tests/sql/minirun/part7/canondata/result.json index ee25c925aa4..5d50b870083 100644 --- a/yql/essentials/tests/sql/minirun/part7/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part7/canondata/result.json @@ -293,6 +293,48 @@ "uri": "https://{canondata_backend}/1903280/44f4f1690f38bce1fadfbce889480224fbb8b527/resource.tar.gz#test.test_blocks-extend-default.txt-Results_/results.txt" } ], + "test.test[blocks-guess_struct-default.txt-Debug]": [ + { + "checksum": "dc695ef63c0f88a81910b94520d24e95", + "size": 672, + "uri": "https://{canondata_backend}/1814674/af6048e526ca90118fc48e8a1171c55d8d01599c/resource.tar.gz#test.test_blocks-guess_struct-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-guess_struct-default.txt-Peephole]": [ + { + "checksum": "503506e157eefe241ea710f344a9a4d3", + "size": 857, + "uri": "https://{canondata_backend}/1814674/af6048e526ca90118fc48e8a1171c55d8d01599c/resource.tar.gz#test.test_blocks-guess_struct-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-guess_struct-default.txt-Results]": [ + { + "checksum": "28718b5e1be812f03ffc37b36f5a484f", + "size": 2907, + "uri": "https://{canondata_backend}/1814674/af6048e526ca90118fc48e8a1171c55d8d01599c/resource.tar.gz#test.test_blocks-guess_struct-default.txt-Results_/results.txt" + } + ], + "test.test[blocks-guess_struct_optional-default.txt-Debug]": [ + { + "checksum": "a39f5af6d371ab3cd348088dfc555581", + "size": 682, + "uri": "https://{canondata_backend}/1814674/af6048e526ca90118fc48e8a1171c55d8d01599c/resource.tar.gz#test.test_blocks-guess_struct_optional-default.txt-Debug_/opt.yql" + } + ], + "test.test[blocks-guess_struct_optional-default.txt-Peephole]": [ + { + "checksum": "04b061f56cff50b6e5e047373ea6d77d", + "size": 807, + "uri": "https://{canondata_backend}/1814674/af6048e526ca90118fc48e8a1171c55d8d01599c/resource.tar.gz#test.test_blocks-guess_struct_optional-default.txt-Peephole_/opt.yql" + } + ], + "test.test[blocks-guess_struct_optional-default.txt-Results]": [ + { + "checksum": "ab943064d130561ae2d2eff39b483c0f", + "size": 1583, + "uri": "https://{canondata_backend}/1814674/af6048e526ca90118fc48e8a1171c55d8d01599c/resource.tar.gz#test.test_blocks-guess_struct_optional-default.txt-Results_/results.txt" + } + ], "test.test[blocks-if_scalar-default.txt-Debug]": [ { "checksum": "b1316cc011f1941633e8e78e1297ac0b", diff --git a/yql/essentials/tests/sql/sql2yql/canondata/result.json b/yql/essentials/tests/sql/sql2yql/canondata/result.json index 3b36e102020..f0e87dec7c7 100644 --- a/yql/essentials/tests/sql/sql2yql/canondata/result.json +++ b/yql/essentials/tests/sql/sql2yql/canondata/result.json @@ -2330,6 +2330,41 @@ "uri": "https://{canondata_backend}/1942100/698d95eec1cbd4e4ada1a8da105c203a7a12bb85/resource.tar.gz#test_sql2yql.test_blocks-frompg_/sql.yql" } ], + "test_sql2yql.test[blocks-guess_struct]": [ + { + "checksum": "84d8c16ade2df9cbf4fafa084f925616", + "size": 1768, + "uri": "https://{canondata_backend}/1942100/59faa31c8c62f57bd9d23c377a9ecd8a3fc1fc84/resource.tar.gz#test_sql2yql.test_blocks-guess_struct_/sql.yql" + } + ], + "test_sql2yql.test[blocks-guess_struct_optional]": [ + { + "checksum": "dabbcbab4b66442b84a804df6ae216dd", + "size": 1678, + "uri": "https://{canondata_backend}/1942100/59faa31c8c62f57bd9d23c377a9ecd8a3fc1fc84/resource.tar.gz#test_sql2yql.test_blocks-guess_struct_optional_/sql.yql" + } + ], + "test_sql2yql.test[blocks-guess_struct_optional_member]": [ + { + "checksum": "54ce491fdb17455668bb6f5bba1b8d16", + "size": 1811, + "uri": "https://{canondata_backend}/1942100/59faa31c8c62f57bd9d23c377a9ecd8a3fc1fc84/resource.tar.gz#test_sql2yql.test_blocks-guess_struct_optional_member_/sql.yql" + } + ], + "test_sql2yql.test[blocks-guess_tuple]": [ + { + "checksum": "f9e25ddbfed1d8d6de147d4567142216", + "size": 1659, + "uri": "https://{canondata_backend}/1899731/617f799adb700d0123a74da1da91c1c62797b1e0/resource.tar.gz#test_sql2yql.test_blocks-guess_tuple_/sql.yql" + } + ], + "test_sql2yql.test[blocks-guess_tuple_optional]": [ + { + "checksum": "b1eab2d46db98c837f877f5dad37478b", + "size": 1669, + "uri": "https://{canondata_backend}/1899731/617f799adb700d0123a74da1da91c1c62797b1e0/resource.tar.gz#test_sql2yql.test_blocks-guess_tuple_optional_/sql.yql" + } + ], "test_sql2yql.test[blocks-if]": [ { "checksum": "2b573fa3534410c28b1273b496c93231", @@ -14019,6 +14054,31 @@ "uri": "file://test_sql_format.test_blocks-frompg_/formatted.sql" } ], + "test_sql_format.test[blocks-guess_struct]": [ + { + "uri": "file://test_sql_format.test_blocks-guess_struct_/formatted.sql" + } + ], + "test_sql_format.test[blocks-guess_struct_optional]": [ + { + "uri": "file://test_sql_format.test_blocks-guess_struct_optional_/formatted.sql" + } + ], + "test_sql_format.test[blocks-guess_struct_optional_member]": [ + { + "uri": "file://test_sql_format.test_blocks-guess_struct_optional_member_/formatted.sql" + } + ], + "test_sql_format.test[blocks-guess_tuple]": [ + { + "uri": "file://test_sql_format.test_blocks-guess_tuple_/formatted.sql" + } + ], + "test_sql_format.test[blocks-guess_tuple_optional]": [ + { + "uri": "file://test_sql_format.test_blocks-guess_tuple_optional_/formatted.sql" + } + ], "test_sql_format.test[blocks-if]": [ { "uri": "file://test_sql_format.test_blocks-if_/formatted.sql" diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_/formatted.sql new file mode 100644 index 00000000000..63d841c814f --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_/formatted.sql @@ -0,0 +1,14 @@ +$structVariantType = Variant<a: Int32, b: String>; + +$data = [ + <|variantValue: Variant(1, 'a', $structVariantType)|>, + <|variantValue: Variant('world', 'b', $structVariantType)|>, +]; + +SELECT + variantValue, + variantValue.a AS aAlternative, + variantValue.b AS bAlternative +FROM + as_table($data) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_optional_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_optional_/formatted.sql new file mode 100644 index 00000000000..dd3e6d4a6d4 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_optional_/formatted.sql @@ -0,0 +1,14 @@ +$structVariantType = Variant<a: Int32, b: String>; + +$optionalVariantData = [ + <|variantValue: Just(Variant(1, 'a', $structVariantType))|>, + <|variantValue: Nothing(OptionalType($structVariantType))|>, + <|variantValue: Just(Variant('hello', 'b', $structVariantType))|>, +]; + +SELECT + variantValue.a AS aAlternative, + variantValue.b AS bAlternative +FROM + as_table($optionalVariantData) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_optional_member_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_optional_member_/formatted.sql new file mode 100644 index 00000000000..ef9a6a154d9 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_struct_optional_member_/formatted.sql @@ -0,0 +1,15 @@ +$variantWithOptionalMemberType = Variant<a: Optional<Int32>, b: String>; + +$optionalVariantWithOptionalMemberData = [ + <|variantValue: Just(Variant(Just(10), 'a', $variantWithOptionalMemberType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), 'a', $variantWithOptionalMemberType))|>, + <|variantValue: Nothing(OptionalType($variantWithOptionalMemberType))|>, + <|variantValue: Just(Variant('world', 'b', $variantWithOptionalMemberType))|>, +]; + +SELECT + variantValue.a AS aAlternative, + variantValue.b AS bAlternative +FROM + as_table($optionalVariantWithOptionalMemberData) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_tuple_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_tuple_/formatted.sql new file mode 100644 index 00000000000..d8117621bda --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_tuple_/formatted.sql @@ -0,0 +1,14 @@ +$tupleVariantType = Variant<Int32, String>; + +$data = [ + <|variantValue: Variant(1, '0', $tupleVariantType)|>, + <|variantValue: Variant('hello', '1', $tupleVariantType)|>, + <|variantValue: Variant(42, '0', $tupleVariantType)|>, +]; + +SELECT + variantValue.0 AS intAlternative, + variantValue.1 AS strAlternative +FROM + as_table($data) +; diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_tuple_optional_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_tuple_optional_/formatted.sql new file mode 100644 index 00000000000..277f91ebf23 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_blocks-guess_tuple_optional_/formatted.sql @@ -0,0 +1,14 @@ +$tupleVariantType = Variant<Int32, String>; + +$optionalData = [ + <|variantValue: Just(Variant(1, '0', $tupleVariantType))|>, + <|variantValue: Nothing(OptionalType($tupleVariantType))|>, + <|variantValue: Just(Variant('hello', '1', $tupleVariantType))|>, +]; + +SELECT + variantValue.0 AS intAlternative, + variantValue.1 AS strAlternative +FROM + as_table($optionalData) +; diff --git a/yql/essentials/tests/sql/suites/blocks/guess_struct.yql b/yql/essentials/tests/sql/suites/blocks/guess_struct.yql new file mode 100644 index 00000000000..7bc063649e5 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/guess_struct.yql @@ -0,0 +1,8 @@ +$structVariantType = Variant<a: Int32, b: String>; + +$data = [ + <|variantValue: Variant(1, "a", $structVariantType)|>, + <|variantValue: Variant("world", "b", $structVariantType)|>, +]; + +SELECT variantValue, variantValue.a AS aAlternative, variantValue.b AS bAlternative FROM as_table($data); diff --git a/yql/essentials/tests/sql/suites/blocks/guess_struct_optional.yql b/yql/essentials/tests/sql/suites/blocks/guess_struct_optional.yql new file mode 100644 index 00000000000..91217f50c54 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/guess_struct_optional.yql @@ -0,0 +1,9 @@ +$structVariantType = Variant<a: Int32, b: String>; + +$optionalVariantData = [ + <|variantValue: Just(Variant(1, "a", $structVariantType))|>, + <|variantValue: Nothing(OptionalType($structVariantType))|>, + <|variantValue: Just(Variant("hello", "b", $structVariantType))|>, +]; + +SELECT variantValue.a AS aAlternative, variantValue.b AS bAlternative FROM as_table($optionalVariantData); diff --git a/yql/essentials/tests/sql/suites/blocks/guess_struct_optional_member.yql b/yql/essentials/tests/sql/suites/blocks/guess_struct_optional_member.yql new file mode 100644 index 00000000000..a6c9baf79a1 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/guess_struct_optional_member.yql @@ -0,0 +1,10 @@ +$variantWithOptionalMemberType = Variant<a: Optional<Int32>, b: String>; + +$optionalVariantWithOptionalMemberData = [ + <|variantValue: Just(Variant(Just(10), "a", $variantWithOptionalMemberType))|>, + <|variantValue: Just(Variant(Nothing(Int32?), "a", $variantWithOptionalMemberType))|>, + <|variantValue: Nothing(OptionalType($variantWithOptionalMemberType))|>, + <|variantValue: Just(Variant("world", "b", $variantWithOptionalMemberType))|>, +]; + +SELECT variantValue.a AS aAlternative, variantValue.b AS bAlternative FROM as_table($optionalVariantWithOptionalMemberData); diff --git a/yql/essentials/tests/sql/suites/blocks/guess_tuple.yql b/yql/essentials/tests/sql/suites/blocks/guess_tuple.yql new file mode 100644 index 00000000000..f112e186783 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/guess_tuple.yql @@ -0,0 +1,9 @@ +$tupleVariantType = Variant<Int32, String>; + +$data = [ + <|variantValue: Variant(1, "0", $tupleVariantType)|>, + <|variantValue: Variant("hello", "1", $tupleVariantType)|>, + <|variantValue: Variant(42, "0", $tupleVariantType)|>, +]; + +SELECT variantValue.0 AS intAlternative, variantValue.1 AS strAlternative FROM as_table($data); diff --git a/yql/essentials/tests/sql/suites/blocks/guess_tuple_optional.yql b/yql/essentials/tests/sql/suites/blocks/guess_tuple_optional.yql new file mode 100644 index 00000000000..12bdf873829 --- /dev/null +++ b/yql/essentials/tests/sql/suites/blocks/guess_tuple_optional.yql @@ -0,0 +1,9 @@ +$tupleVariantType = Variant<Int32, String>; + +$optionalData = [ + <|variantValue: Just(Variant(1, "0", $tupleVariantType))|>, + <|variantValue: Nothing(OptionalType($tupleVariantType))|>, + <|variantValue: Just(Variant("hello", "1", $tupleVariantType))|>, +]; + +SELECT variantValue.0 AS intAlternative, variantValue.1 AS strAlternative FROM as_table($optionalData); |
