compile_mkql.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #include "compile_mkql.h"
  2. #include <yql/essentials/providers/common/mkql/yql_provider_mkql.h>
  3. #include <yql/essentials/providers/common/mkql/yql_type_mkql.h>
  4. #include <yql/essentials/core/yql_user_data_storage.h>
  5. #include <yql/essentials/public/purecalc/common/names.h>
  6. #include <util/stream/file.h>
  7. namespace NYql::NPureCalc {
  8. namespace {
  9. NCommon::IMkqlCallableCompiler::TCompiler MakeSelfCallableCompiler() {
  10. return [](const TExprNode& node, NCommon::TMkqlBuildContext& ctx) {
  11. MKQL_ENSURE(node.ChildrenSize() == 1, "Self takes exactly 1 argument");
  12. const auto* argument = node.Child(0);
  13. MKQL_ENSURE(argument->IsAtom(), "Self argument must be atom");
  14. ui32 inputIndex = 0;
  15. MKQL_ENSURE(TryFromString(argument->Content(), inputIndex), "Self argument must be UI32");
  16. auto type = ctx.BuildType(node, *node.GetTypeAnn());
  17. NKikimr::NMiniKQL::TCallableBuilder call(ctx.ProgramBuilder.GetTypeEnvironment(), node.Content(), type);
  18. call.Add(ctx.ProgramBuilder.NewDataLiteral<ui32>(inputIndex));
  19. return NKikimr::NMiniKQL::TRuntimeNode(call.Build(), false);
  20. };
  21. }
  22. NCommon::IMkqlCallableCompiler::TCompiler MakeFilePathCallableCompiler(const TUserDataTable& userData) {
  23. return [&](const TExprNode& node, NCommon::TMkqlBuildContext& ctx) {
  24. const TString name(node.Child(0)->Content());
  25. auto block = TUserDataStorage::FindUserDataBlock(userData, TUserDataKey::File(name));
  26. if (!block) {
  27. auto blockKey = TUserDataKey::File(GetDefaultFilePrefix() + name);
  28. block = TUserDataStorage::FindUserDataBlock(userData, blockKey);
  29. }
  30. MKQL_ENSURE(block, "file not found: " << name);
  31. MKQL_ENSURE(block->Type == EUserDataType::PATH,
  32. "FilePath not supported for non-filesystem user data, name: "
  33. << name << ", block type: " << block->Type);
  34. return ctx.ProgramBuilder.NewDataLiteral<NKikimr::NUdf::EDataSlot::String>(block->Data);
  35. };
  36. }
  37. NCommon::IMkqlCallableCompiler::TCompiler MakeFileContentCallableCompiler(const TUserDataTable& userData) {
  38. return [&](const TExprNode& node, NCommon::TMkqlBuildContext& ctx) {
  39. const TString name(node.Child(0)->Content());
  40. auto block = TUserDataStorage::FindUserDataBlock(userData, TUserDataKey::File(name));
  41. if (!block) {
  42. auto blockKey = TUserDataKey::File(GetDefaultFilePrefix() + name);
  43. block = TUserDataStorage::FindUserDataBlock(userData, blockKey);
  44. }
  45. MKQL_ENSURE(block, "file not found: " << name);
  46. if (block->Type == EUserDataType::PATH) {
  47. auto content = TFileInput(block->Data).ReadAll();
  48. return ctx.ProgramBuilder.NewDataLiteral<NKikimr::NUdf::EDataSlot::String>(content);
  49. } else if (block->Type == EUserDataType::RAW_INLINE_DATA) {
  50. return ctx.ProgramBuilder.NewDataLiteral<NKikimr::NUdf::EDataSlot::String>(block->Data);
  51. } else {
  52. // TODO support EUserDataType::URL
  53. MKQL_ENSURE(false, "user data blocks of type URL are not supported by FileContent: " << name);
  54. Y_UNREACHABLE();
  55. }
  56. };
  57. }
  58. NCommon::IMkqlCallableCompiler::TCompiler MakeFolderPathCallableCompiler(const TUserDataTable& userData) {
  59. return [&](const TExprNode& node, NCommon::TMkqlBuildContext& ctx) {
  60. const TString name(node.Child(0)->Content());
  61. auto folderName = TUserDataStorage::MakeFolderName(name);
  62. TMaybe<TString> folderPath;
  63. for (const auto& x : userData) {
  64. if (!x.first.Alias().StartsWith(folderName)) {
  65. continue;
  66. }
  67. MKQL_ENSURE(x.second.Type == EUserDataType::PATH,
  68. "FilePath not supported for non-file data block, name: "
  69. << x.first.Alias() << ", block type: " << x.second.Type);
  70. auto pathPrefixLength = x.second.Data.size() - (x.first.Alias().size() - folderName.size());
  71. auto newFolderPath = x.second.Data.substr(0, pathPrefixLength);
  72. if (!folderPath) {
  73. folderPath = newFolderPath;
  74. } else {
  75. MKQL_ENSURE(*folderPath == newFolderPath,
  76. "file " << x.second.Data << " is out of directory " << *folderPath);
  77. }
  78. }
  79. return ctx.ProgramBuilder.NewDataLiteral<NKikimr::NUdf::EDataSlot::String>(*folderPath);
  80. };
  81. }
  82. }
  83. NKikimr::NMiniKQL::TRuntimeNode CompileMkql(const TExprNode::TPtr& exprRoot, TExprContext& exprCtx,
  84. const NKikimr::NMiniKQL::IFunctionRegistry& funcRegistry, const NKikimr::NMiniKQL::TTypeEnvironment& env, const TUserDataTable& userData, NCommon::TMemoizedTypesMap* typeMemoization)
  85. {
  86. NCommon::TMkqlCommonCallableCompiler compiler;
  87. compiler.AddCallable(PurecalcInputCallableName, MakeSelfCallableCompiler());
  88. compiler.AddCallable(PurecalcBlockInputCallableName, MakeSelfCallableCompiler());
  89. compiler.OverrideCallable("FileContent", MakeFileContentCallableCompiler(userData));
  90. compiler.OverrideCallable("FilePath", MakeFilePathCallableCompiler(userData));
  91. compiler.OverrideCallable("FolderPath", MakeFolderPathCallableCompiler(userData));
  92. // Prepare build context
  93. NKikimr::NMiniKQL::TProgramBuilder pgmBuilder(env, funcRegistry);
  94. NCommon::TMkqlBuildContext buildCtx(compiler, pgmBuilder, exprCtx, /*lambdaId*/0, /*args*/{}, typeMemoization);
  95. // Build the root MKQL node
  96. return NCommon::MkqlBuildExpr(*exprRoot, buildCtx);
  97. }
  98. } // NYql::NPureCalc