yql_config_provider.cpp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. #include "yql_config_provider.h"
  2. #include <yql/essentials/providers/common/provider/yql_provider_names.h>
  3. #include <yql/essentials/providers/common/provider/yql_data_provider_impl.h>
  4. #include <yql/essentials/providers/common/proto/gateways_config.pb.h>
  5. #include <yql/essentials/providers/common/provider/yql_provider.h>
  6. #include <yql/essentials/providers/common/activation/yql_activation.h>
  7. #include <yql/essentials/core/expr_nodes/yql_expr_nodes.h>
  8. #include <yql/essentials/core/yql_execution.h>
  9. #include <yql/essentials/core/yql_expr_optimize.h>
  10. #include <yql/essentials/core/yql_expr_type_annotation.h>
  11. #include <yql/essentials/core/type_ann/type_ann_core.h>
  12. #include <yql/essentials/ast/yql_gc_nodes.h>
  13. #include <yql/essentials/utils/log/log.h>
  14. #include <yql/essentials/utils/fetch/fetch.h>
  15. #include <yql/essentials/utils/retry.h>
  16. #include <library/cpp/json/json_reader.h>
  17. #include <util/string/cast.h>
  18. #include <util/generic/hash.h>
  19. #include <util/generic/utility.h>
  20. #include <util/string/builder.h>
  21. #include <vector>
  22. namespace NYql {
  23. namespace {
  24. using namespace NNodes;
  25. class TConfigCallableExecutionTransformer : public TSyncTransformerBase {
  26. public:
  27. TConfigCallableExecutionTransformer(const TTypeAnnotationContext& types)
  28. : Types(types)
  29. {
  30. Y_UNUSED(Types);
  31. }
  32. TStatus DoTransform(TExprNode::TPtr input, TExprNode::TPtr& output, TExprContext& ctx) final {
  33. output = input;
  34. YQL_ENSURE(input->Type() == TExprNode::Callable);
  35. if (input->Content() == "Pull") {
  36. auto requireStatus = RequireChild(*input, 0);
  37. if (requireStatus.Level != TStatus::Ok) {
  38. return requireStatus;
  39. }
  40. IDataProvider::TFillSettings fillSettings = NCommon::GetFillSettings(*input);
  41. YQL_ENSURE(fillSettings.Format == IDataProvider::EResultFormat::Yson);
  42. NYson::EYsonFormat ysonFormat = NCommon::GetYsonFormat(fillSettings);
  43. auto nodeToPull = input->Child(0)->Child(0);
  44. if (nodeToPull->IsCallable(ConfReadName)) {
  45. auto key = nodeToPull->Child(2);
  46. auto tag = key->Child(0)->Child(0)->Content();
  47. if (tag == "data_sinks" || tag == "data_sources") {
  48. TStringStream out;
  49. NYson::TYsonWriter writer(&out, ysonFormat);
  50. writer.OnBeginMap();
  51. writer.OnKeyedItem("Data");
  52. writer.OnBeginList();
  53. if (tag == "data_sinks") {
  54. writer.OnListItem();
  55. writer.OnStringScalar(KikimrProviderName);
  56. writer.OnListItem();
  57. writer.OnStringScalar(YtProviderName);
  58. writer.OnListItem();
  59. writer.OnStringScalar(ResultProviderName);
  60. } else if (tag == "data_sources") {
  61. writer.OnListItem();
  62. writer.OnStringScalar(KikimrProviderName);
  63. writer.OnListItem();
  64. writer.OnStringScalar(YtProviderName);
  65. writer.OnListItem();
  66. writer.OnStringScalar(ConfigProviderName);
  67. }
  68. writer.OnEndList();
  69. writer.OnEndMap();
  70. input->SetResult(ctx.NewAtom(input->Pos(), out.Str()));
  71. input->SetState(TExprNode::EState::ExecutionComplete);
  72. return TStatus::Ok;
  73. } else {
  74. ctx.AddError(TIssue(ctx.GetPosition(input->Pos()), TStringBuilder() << "Unsupported tag: " << tag));
  75. return TStatus::Error;
  76. }
  77. }
  78. ctx.AddError(TIssue(ctx.GetPosition(input->Pos()), TStringBuilder() << "Unknown node to pull, type: "
  79. << nodeToPull->Type() << ", content: " << nodeToPull->Content()));
  80. return TStatus::Error;
  81. }
  82. if (input->Content() == ConfReadName) {
  83. auto requireStatus = RequireChild(*input, 0);
  84. if (requireStatus.Level != TStatus::Ok) {
  85. return requireStatus;
  86. }
  87. input->SetState(TExprNode::EState::ExecutionComplete);
  88. input->SetResult(ctx.NewWorld(input->Pos()));
  89. return TStatus::Ok;
  90. }
  91. if (input->Content() == ConfigureName) {
  92. auto requireStatus = RequireChild(*input, 0);
  93. if (requireStatus.Level != TStatus::Ok) {
  94. return requireStatus;
  95. }
  96. input->SetState(TExprNode::EState::ExecutionComplete);
  97. input->SetResult(ctx.NewWorld(input->Pos()));
  98. return TStatus::Ok;
  99. }
  100. ctx.AddError(TIssue(ctx.GetPosition(input->Pos()), TStringBuilder() << "Failed to execute node: " << input->Content()));
  101. return TStatus::Error;
  102. }
  103. void Rewind() final {
  104. }
  105. private:
  106. const TTypeAnnotationContext& Types;
  107. };
  108. class TConfigProvider : public TDataProviderBase {
  109. public:
  110. struct TFunctions {
  111. THashSet<TStringBuf> Names;
  112. TFunctions() {
  113. Names.insert(ConfReadName);
  114. }
  115. };
  116. TConfigProvider(TTypeAnnotationContext& types, const TGatewaysConfig* config, const TString& username, const TAllowSettingPolicy& policy)
  117. : Types(types)
  118. , CoreConfig(config && config->HasYqlCore() ? &config->GetYqlCore() : nullptr)
  119. , Username(username)
  120. , Policy(policy)
  121. {}
  122. TStringBuf GetName() const override {
  123. return ConfigProviderName;
  124. }
  125. bool Initialize(TExprContext& ctx) override {
  126. std::unordered_set<std::string_view> groups;
  127. if (Types.Credentials != nullptr) {
  128. groups.insert(Types.Credentials->GetGroups().begin(), Types.Credentials->GetGroups().end());
  129. }
  130. auto filter = [this, groups = std::move(groups)](const TCoreAttr& attr) {
  131. if (!attr.HasActivation() || !Username) {
  132. return true;
  133. }
  134. if (NConfig::Allow(attr.GetActivation(), Username, groups)) {
  135. Statistics.Entries.emplace_back(TStringBuilder() << "Activation:" << attr.GetName(), 0, 0, 0, 0, 1);
  136. return true;
  137. }
  138. return false;
  139. };
  140. if (CoreConfig) {
  141. TPosition pos;
  142. for (auto& flag: CoreConfig->GetFlags()) {
  143. if (filter(flag)) {
  144. TVector<TStringBuf> args;
  145. for (auto& arg: flag.GetArgs()) {
  146. args.push_back(arg);
  147. }
  148. if (!ApplyFlag(pos, flag.GetName(), args, ctx)) {
  149. return false;
  150. }
  151. }
  152. }
  153. }
  154. return true;
  155. }
  156. bool CollectStatistics(NYson::TYsonWriter& writer, bool totalOnly) override {
  157. if (Statistics.Entries.empty()) {
  158. return false;
  159. }
  160. THashMap<ui32, TOperationStatistics> tmp;
  161. tmp.emplace(Max<ui32>(), Statistics);
  162. NCommon::WriteStatistics(writer, totalOnly, tmp);
  163. return true;
  164. }
  165. bool ValidateParameters(TExprNode& node, TExprContext& ctx, TMaybe<TString>& cluster) override {
  166. if (!EnsureArgsCount(node, 1, ctx)) {
  167. return false;
  168. }
  169. cluster = Nothing();
  170. return true;
  171. }
  172. bool MatchCategory(const TExprNode& node) {
  173. return (node.Child(1)->Child(0)->Content() == ConfigProviderName);
  174. }
  175. bool CanParse(const TExprNode& node) override {
  176. if (ConfigProviderFunctions().contains(node.Content()) ||
  177. node.Content() == ConfigureName)
  178. {
  179. return MatchCategory(node);
  180. }
  181. return false;
  182. }
  183. IGraphTransformer& GetConfigurationTransformer() override {
  184. if (ConfigurationTransformer) {
  185. return *ConfigurationTransformer;
  186. }
  187. ConfigurationTransformer = CreateFunctorTransformer(
  188. [this](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) -> IGraphTransformer::TStatus {
  189. output = input;
  190. if (ctx.Step.IsDone(TExprStep::Configure)) {
  191. return IGraphTransformer::TStatus::Ok;
  192. }
  193. bool hasPendingEvaluations = false;
  194. TOptimizeExprSettings settings(nullptr);
  195. settings.VisitChanges = true;
  196. auto status = OptimizeExpr(input, output, [&](const TExprNode::TPtr& node, TExprContext& ctx) -> TExprNode::TPtr {
  197. auto res = node;
  198. if (!hasPendingEvaluations && node->Content() == ConfigureName) {
  199. if (!EnsureMinArgsCount(*node, 2, ctx)) {
  200. return {};
  201. }
  202. if (!node->Child(1)->IsCallable("DataSource")) {
  203. return node;
  204. }
  205. if (node->Child(1)->Child(0)->Content() != ConfigProviderName) {
  206. return node;
  207. }
  208. if (!EnsureMinArgsCount(*node, 3, ctx)) {
  209. return {};
  210. }
  211. if (!EnsureAtom(*node->Child(2), ctx)) {
  212. return {};
  213. }
  214. TStringBuf command = node->Child(2)->Content();
  215. if (command.length() && '_' == command[0]) {
  216. ctx.AddError(TIssue(ctx.GetPosition(node->Child(2)->Pos()), "Flags started with underscore are not allowed"));
  217. return {};
  218. }
  219. TVector<TStringBuf> args;
  220. for (size_t i = 3; i < node->ChildrenSize(); ++i) {
  221. if (node->Child(i)->IsCallable("EvaluateAtom")) {
  222. hasPendingEvaluations = true;
  223. return res;
  224. }
  225. if (!EnsureAtom(*node->Child(i), ctx)) {
  226. return {};
  227. }
  228. args.push_back(node->Child(i)->Content());
  229. }
  230. if (!ApplyFlag(ctx.GetPosition(node->Child(2)->Pos()), command, args, ctx)) {
  231. return {};
  232. }
  233. if (command == "PureDataSource") {
  234. if (Types.PureResultDataSource != node->Child(3)->Content()) {
  235. res = ctx.ChangeChild(*node, 3, ctx.RenameNode(*node->Child(3), Types.PureResultDataSource));
  236. }
  237. }
  238. }
  239. return res;
  240. }, ctx, settings);
  241. return status;
  242. });
  243. return *ConfigurationTransformer;
  244. }
  245. IGraphTransformer& GetTypeAnnotationTransformer(bool instantOnly) override {
  246. Y_UNUSED(instantOnly);
  247. if (!TypeAnnotationTransformer) {
  248. TypeAnnotationTransformer = CreateFunctorTransformer(
  249. [&](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) -> IGraphTransformer::TStatus {
  250. output = input;
  251. if (input->Content() == ConfReadName) {
  252. if (!EnsureWorldType(*input->Child(0), ctx)) {
  253. return IGraphTransformer::TStatus::Error;
  254. }
  255. if (!EnsureSpecificDataSource(*input->Child(1), ConfigProviderName, ctx)) {
  256. return IGraphTransformer::TStatus::Error;
  257. }
  258. auto key = input->Child(2);
  259. if (!key->IsCallable("Key")) {
  260. ctx.AddError(TIssue(ctx.GetPosition(key->Pos()), "Expected key"));
  261. return IGraphTransformer::TStatus::Error;
  262. }
  263. if (key->ChildrenSize() == 0) {
  264. ctx.AddError(TIssue(ctx.GetPosition(key->Pos()), "Empty key is not allowed"));
  265. return IGraphTransformer::TStatus::Error;
  266. }
  267. auto tag = key->Child(0)->Child(0)->Content();
  268. if (key->Child(0)->ChildrenSize() > 1) {
  269. ctx.AddError(TIssue(ctx.GetPosition(key->Child(0)->Pos()), "Only tag must be specified"));
  270. return IGraphTransformer::TStatus::Error;
  271. }
  272. if (key->ChildrenSize() > 1) {
  273. ctx.AddError(TIssue(ctx.GetPosition(key->Pos()), "Too many tags"));
  274. return IGraphTransformer::TStatus::Error;
  275. }
  276. auto fields = input->Child(3);
  277. if (!EnsureTuple(*fields, ctx)) {
  278. return IGraphTransformer::TStatus::Error;
  279. }
  280. if (fields->ChildrenSize() != 0) {
  281. ctx.AddError(TIssue(ctx.GetPosition(fields->Pos()), "Fields tuple must be empty"));
  282. return IGraphTransformer::TStatus::Error;
  283. }
  284. if (!input->Child(3)->GetTypeAnn() || !input->Child(3)->IsComposable()) {
  285. ctx.AddError(TIssue(ctx.GetPosition(input->Child(3)->Pos()), "Expected composable data"));
  286. return IGraphTransformer::TStatus::Error;
  287. }
  288. auto settings = input->Child(4);
  289. if (!EnsureTuple(*settings, ctx)) {
  290. return IGraphTransformer::TStatus::Error;
  291. }
  292. if (settings->ChildrenSize() != 0) {
  293. ctx.AddError(TIssue(ctx.GetPosition(settings->Pos()), "Unsupported settings"));
  294. return IGraphTransformer::TStatus::Error;
  295. }
  296. auto stringAnnotation = ctx.MakeType<TDataExprType>(EDataSlot::String);
  297. auto listOfString = ctx.MakeType<TListExprType>(stringAnnotation);
  298. TTypeAnnotationNode::TListType children;
  299. children.push_back(input->Child(0)->GetTypeAnn());
  300. if (tag == "data_sources" || tag == "data_sinks") {
  301. children.push_back(listOfString);
  302. } else {
  303. ctx.AddError(TIssue(ctx.GetPosition(key->Pos()), TStringBuilder() << "Unknown tag: " << tag));
  304. return IGraphTransformer::TStatus::Error;
  305. }
  306. auto tupleAnn = ctx.MakeType<TTupleExprType>(children);
  307. input->SetTypeAnn(tupleAnn);
  308. return IGraphTransformer::TStatus::Ok;
  309. }
  310. else if (input->Content() == ConfigureName) {
  311. if (!EnsureWorldType(*input->Child(0), ctx)) {
  312. return IGraphTransformer::TStatus::Error;
  313. }
  314. input->SetTypeAnn(input->Child(0)->GetTypeAnn());
  315. return IGraphTransformer::TStatus::Ok;
  316. }
  317. ctx.AddError(TIssue(ctx.GetPosition(input->Pos()), TStringBuilder() << "(Config) Unsupported function: " << input->Content()));
  318. return IGraphTransformer::TStatus::Error;
  319. });
  320. }
  321. return *TypeAnnotationTransformer;
  322. }
  323. TExprNode::TPtr RewriteIO(const TExprNode::TPtr& node, TExprContext& ctx) override {
  324. auto read = node->Child(0);
  325. TString newName;
  326. if (read->Content() == ReadName) {
  327. newName = ConfReadName;
  328. }
  329. else {
  330. YQL_ENSURE(false, "Expected Read!");
  331. }
  332. YQL_CLOG(INFO, ProviderConfig) << "RewriteIO";
  333. auto newRead = ctx.RenameNode(*read, newName);
  334. auto retChildren = node->ChildrenList();
  335. retChildren[0] = newRead;
  336. return ctx.ChangeChildren(*node, std::move(retChildren));
  337. }
  338. bool CanPullResult(const TExprNode& node, TSyncMap& syncList, bool& canRef) override {
  339. Y_UNUSED(syncList);
  340. if (node.IsCallable(RightName)) {
  341. if (node.Child(0)->IsCallable(ConfReadName)) {
  342. canRef = false;
  343. return true;
  344. }
  345. }
  346. return false;
  347. }
  348. bool CanExecute(const TExprNode& node) override {
  349. if (ConfigProviderFunctions().contains(node.Content()) ||
  350. node.Content() == ConfigureName)
  351. {
  352. return MatchCategory(node);
  353. }
  354. return false;
  355. }
  356. IGraphTransformer& GetCallableExecutionTransformer() override {
  357. if (!CallableExecutionTransformer) {
  358. CallableExecutionTransformer = new TConfigCallableExecutionTransformer(Types);
  359. }
  360. return *CallableExecutionTransformer;
  361. }
  362. bool GetDependencies(const TExprNode& node, TExprNode::TListType& children, bool compact) override {
  363. Y_UNUSED(compact);
  364. if (CanExecute(node)) {
  365. children.push_back(node.ChildPtr(0));
  366. }
  367. return false;
  368. }
  369. void WritePullDetails(const TExprNode& node, NYson::TYsonWriter& writer) override {
  370. YQL_ENSURE(node.IsCallable(RightName));
  371. writer.OnKeyedItem("PullOperation");
  372. writer.OnStringScalar(node.Child(0)->Content());
  373. }
  374. TString GetProviderPath(const TExprNode& node) override {
  375. Y_UNUSED(node);
  376. return "config";
  377. }
  378. private:
  379. bool IsSettingAllowed(const TPosition& pos, TStringBuf name, TExprContext& ctx) {
  380. if (Policy && !Policy(name)) {
  381. ctx.AddError(TIssue(pos, TStringBuilder() << "Changing setting " << name << " is not allowed"));
  382. return false;
  383. }
  384. return true;
  385. }
  386. bool ApplyFlag(const TPosition& pos, const TStringBuf name, const TVector<TStringBuf>& args, TExprContext& ctx) {
  387. if (!IsSettingAllowed(pos, name, ctx)) {
  388. return false;
  389. }
  390. if (name == "UnsecureCredential") {
  391. if (!AddCredential(pos, args, ctx)) {
  392. return false;
  393. }
  394. } else if (name == "ImportUdfs") {
  395. if (!ImportUdfs(pos, args, ctx)) {
  396. return false;
  397. }
  398. } else if (name == "AddFileByUrl") {
  399. if (!AddFileByUrl(pos, args, ctx)) {
  400. return false;
  401. }
  402. } else if (name == "SetFileOption") {
  403. if (!SetFileOption(pos, args, ctx)) {
  404. return false;
  405. }
  406. } else if (name == "AddFolderByUrl") {
  407. if (!AddFolderByUrl(pos, args, ctx)) {
  408. return false;
  409. }
  410. } else if (name == "SetPackageVersion") {
  411. if (!SetPackageVersion(pos, args, ctx)) {
  412. return false;
  413. }
  414. }
  415. else if (name == "ValidateUdf") {
  416. if (args.size() != 1) {
  417. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  418. return false;
  419. }
  420. try {
  421. Types.ValidateMode = NKikimr::NUdf::ValidateModeByStr(TString(args[0]));
  422. } catch (const yexception& err) {
  423. ctx.AddError(TIssue(pos, TStringBuilder() << err.AsStrBuf() << ", available modes: " << NKikimr::NUdf::ValidateModeAvailables()));
  424. return false;
  425. }
  426. }
  427. else if (name == "LLVM_OFF") {
  428. if (args.size() != 0) {
  429. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  430. return false;
  431. }
  432. Types.OptLLVM = "OFF";
  433. }
  434. else if (name == "LLVM") {
  435. if (args.size() > 1) {
  436. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  437. return false;
  438. }
  439. Types.OptLLVM = args.empty() ? TString() : TString(args[0]);
  440. }
  441. else if (name == "NodesAllocationLimit") {
  442. if (args.size() != 1) {
  443. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  444. return false;
  445. }
  446. if (!TryFromString(args[0], ctx.NodesAllocationLimit)) {
  447. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  448. return false;
  449. }
  450. }
  451. else if (name == "StringsAllocationLimit") {
  452. if (args.size() != 1) {
  453. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  454. return false;
  455. }
  456. if (!TryFromString(args[0], ctx.StringsAllocationLimit)) {
  457. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  458. return false;
  459. }
  460. }
  461. else if (name == "RepeatTransformLimit") {
  462. if (args.size() != 1) {
  463. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  464. return false;
  465. }
  466. if (!TryFromString(args[0], ctx.RepeatTransformLimit)) {
  467. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  468. return false;
  469. }
  470. }
  471. else if (name == "TypeAnnNodeRepeatLimit") {
  472. if (args.size() != 1) {
  473. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  474. return false;
  475. }
  476. if (!TryFromString(args[0], ctx.TypeAnnNodeRepeatLimit)) {
  477. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  478. return false;
  479. }
  480. }
  481. else if (name == "PureDataSource") {
  482. if (args.size() != 1) {
  483. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  484. return false;
  485. }
  486. auto dataSource = args[0];
  487. if (Find(Types.AvailablePureResultDataSources, dataSource) == Types.AvailablePureResultDataSources.end()) {
  488. ctx.AddError(TIssue(pos, TStringBuilder() << "Unsupported datasource for result provider: " << dataSource));
  489. return false;
  490. }
  491. if (auto p = Types.DataSourceMap.FindPtr(dataSource)) {
  492. if ((*p)->GetName() != dataSource) {
  493. dataSource = (*p)->GetName();
  494. }
  495. } else {
  496. ctx.AddError(TIssue(pos, TStringBuilder() << "Unknown datasource for result provider: " << dataSource));
  497. return false;
  498. }
  499. Types.PureResultDataSource = dataSource;
  500. }
  501. else if (name == "FullResultDataSink") {
  502. if (args.size() != 1) {
  503. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  504. return false;
  505. }
  506. auto dataSink = args[0];
  507. if (auto p = Types.DataSinkMap.FindPtr(dataSink)) {
  508. if ((*p)->GetName() != dataSink) {
  509. dataSink = (*p)->GetName();
  510. }
  511. } else {
  512. ctx.AddError(TIssue(pos, TStringBuilder() << "Unknown datasink for full result provider: " << dataSink));
  513. return false;
  514. }
  515. Types.FullResultDataSink = dataSink;
  516. }
  517. else if (name == "Diagnostics") {
  518. if (args.size() != 0) {
  519. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  520. return false;
  521. }
  522. Types.Diagnostics = true;
  523. }
  524. else if (name == TStringBuf("Warning")) {
  525. if (!SetWarningRule(pos, args, ctx)) {
  526. return false;
  527. }
  528. }
  529. else if (name == "UdfSupportsYield") {
  530. if (args.size() > 1) {
  531. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  532. return false;
  533. }
  534. bool res = true;
  535. if (!args.empty()) {
  536. if (!TryFromString(args[0], res)) {
  537. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected bool, but got: " << args[0]));
  538. return false;
  539. }
  540. }
  541. Types.UdfSupportsYield = res;
  542. }
  543. else if (name == "EvaluateForLimit") {
  544. if (args.size() != 1) {
  545. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  546. return false;
  547. }
  548. if (!TryFromString(args[0], Types.EvaluateForLimit)) {
  549. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  550. return false;
  551. }
  552. }
  553. else if (name == "EvaluateParallelForLimit") {
  554. if (args.size() != 1) {
  555. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  556. return false;
  557. }
  558. if (!TryFromString(args[0], Types.EvaluateParallelForLimit)) {
  559. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  560. return false;
  561. }
  562. }
  563. else if (name == "DisablePullUpFlatMapOverJoin" || name == "PullUpFlatMapOverJoin") {
  564. if (args.size() != 0) {
  565. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  566. return false;
  567. }
  568. Types.PullUpFlatMapOverJoin = (name == "PullUpFlatMapOverJoin");
  569. } else if (name == "DisableFilterPushdownOverJoinOptionalSide" || name == "FilterPushdownOverJoinOptionalSide") {
  570. if (args.size() != 0) {
  571. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  572. return false;
  573. }
  574. Types.FilterPushdownOverJoinOptionalSide = (name == "FilterPushdownOverJoinOptionalSide");
  575. } else if (name == "RotateJoinTree") {
  576. if (args.size() > 1) {
  577. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  578. return false;
  579. }
  580. bool res = true;
  581. if (!args.empty()) {
  582. if (!TryFromString(args[0], res)) {
  583. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected bool, but got: " << args[0]));
  584. return false;
  585. }
  586. }
  587. Types.RotateJoinTree = res;
  588. }
  589. else if (name == "SQL") {
  590. if (args.size() > 1) {
  591. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  592. return false;
  593. }
  594. Types.DeprecatedSQL = (args[0] == "0");
  595. }
  596. else if (name == "DisableConstraintCheck") {
  597. if (args.empty()) {
  598. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at least 1 argument, but got " << args.size()));
  599. return false;
  600. }
  601. for (auto arg: args) {
  602. Types.DisableConstraintCheck.emplace(arg);
  603. }
  604. }
  605. else if (name == "EnableConstraintCheck") {
  606. if (args.empty()) {
  607. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at least 1 argument, but got " << args.size()));
  608. return false;
  609. }
  610. for (auto arg: args) {
  611. Types.DisableConstraintCheck.erase(TString{arg});
  612. }
  613. }
  614. else if (name == "DisableConstraints") {
  615. if (args.empty()) {
  616. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at least 1 argument, but got " << args.size()));
  617. return false;
  618. }
  619. for (auto arg: args) {
  620. ctx.DisabledConstraints.emplace(arg);
  621. }
  622. }
  623. else if (name == "EnableConstraints") {
  624. if (args.empty()) {
  625. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at least 1 argument, but got " << args.size()));
  626. return false;
  627. }
  628. for (auto arg: args) {
  629. ctx.DisabledConstraints.erase(arg);
  630. }
  631. }
  632. else if (name == "UseTableMetaFromGraph") {
  633. if (args.size() > 1) {
  634. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  635. return false;
  636. }
  637. bool res = true;
  638. if (!args.empty()) {
  639. if (!TryFromString(args[0], res)) {
  640. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected bool, but got: " << args[0]));
  641. return false;
  642. }
  643. }
  644. Types.UseTableMetaFromGraph = res;
  645. }
  646. else if (name == "DiscoveryMode") {
  647. if (args.size() != 0) {
  648. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  649. return false;
  650. }
  651. Types.DiscoveryMode = true;
  652. }
  653. else if (name == "EnableSystemColumns") {
  654. if (args.size() != 0) {
  655. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  656. return false;
  657. }
  658. }
  659. else if (name == "UdfIgnoreCase" || name == "UdfStrictCase") {
  660. if (args.size() != 0) {
  661. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  662. return false;
  663. }
  664. if (!Types.UdfIndex) {
  665. ctx.AddError(TIssue(pos, "UdfIndex is not available"));
  666. return false;
  667. }
  668. Types.UdfIndex->SetCaseSentiveSearch(name == "UdfStrictCase");
  669. } else if (name == "DqEngine") {
  670. if (args.size() != 1) {
  671. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  672. return false;
  673. }
  674. auto arg = TString{args[0]};
  675. if (Types.EngineType == EEngineType::Ytflow) {
  676. if (arg == "force") {
  677. ctx.AddError(TIssue(pos, TStringBuilder()
  678. << "Expected `disable|auto` argument for DqEngine pragma "
  679. << "with Engine pragma argument `ytflow`"));
  680. return false;
  681. }
  682. arg = "disable";
  683. } else if (Types.EngineType == EEngineType::Dq) {
  684. arg = "force";
  685. }
  686. if (Find(Types.AvailablePureResultDataSources, DqProviderName) == Types.AvailablePureResultDataSources.end() || arg == "disable") {
  687. ; // reserved
  688. } else if (arg == "auto") {
  689. Types.PureResultDataSource = DqProviderName;
  690. Types.ForceDq = false;
  691. } else if (arg == "force") {
  692. Types.PureResultDataSource = DqProviderName;
  693. Types.ForceDq = true;
  694. } else {
  695. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected `disable|auto|force', but got: " << args[0]));
  696. return false;
  697. }
  698. }
  699. else if (name == "IssueCountLimit") {
  700. if (args.size() != 1) {
  701. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  702. return false;
  703. }
  704. size_t limit = 0;
  705. if (!TryFromString(args[0], limit)) {
  706. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected unsigned integer, but got: " << args[0]));
  707. return false;
  708. }
  709. ctx.IssueManager.SetIssueCountLimit(limit);
  710. }
  711. else if (name == "StrictTableProps") {
  712. if (args.size() != 0) {
  713. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  714. return false;
  715. }
  716. Types.StrictTableProps = true;
  717. }
  718. else if (name == "DisableStrictTableProps") {
  719. if (args.size() != 0) {
  720. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  721. return false;
  722. }
  723. Types.StrictTableProps = false;
  724. }
  725. else if (name == "GeobaseDownloadUrl") {
  726. if (args.size() != 1) {
  727. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  728. return false;
  729. }
  730. auto& userDataBlock = (Types.UserDataStorageCrutches[TUserDataKey::File(TStringBuf("/home/geodata6.bin"))] = TUserDataBlock{EUserDataType::URL, {}, TString(args[0]), {}, {}});
  731. userDataBlock.Usage.Set(EUserDataBlockUsage::Path);
  732. }
  733. else if (name == "JsonQueryReturnsJsonDocument" || name == "DisableJsonQueryReturnsJsonDocument") {
  734. if (args.size() != 0) {
  735. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  736. return false;
  737. }
  738. Types.JsonQueryReturnsJsonDocument = (name == "JsonQueryReturnsJsonDocument");
  739. }
  740. else if (name == "OrderedColumns" || name == "DisableOrderedColumns") {
  741. if (args.size() != 0) {
  742. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  743. return false;
  744. }
  745. Types.OrderedColumns = (name == "OrderedColumns");
  746. }
  747. else if (name == "FolderSubDirsLimit") {
  748. if (args.size() != 1) {
  749. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 1 argument, but got " << args.size()));
  750. return false;
  751. }
  752. if (!TryFromString(args[0], Types.FolderSubDirsLimit)) {
  753. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  754. return false;
  755. }
  756. }
  757. else if (name == "YsonCastToString" || name == "DisableYsonCastToString") {
  758. if (args.size() != 0) {
  759. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  760. return false;
  761. }
  762. Types.YsonCastToString = (name == "YsonCastToString");
  763. }
  764. else if (name == "UseBlocks" || name == "DisableUseBlocks") {
  765. if (args.size() != 0) {
  766. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  767. return false;
  768. }
  769. Types.UseBlocks = (name == "UseBlocks");
  770. }
  771. else if (name == "PgEmitAggApply" || name == "DisablePgEmitAggApply") {
  772. if (args.size() != 0) {
  773. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  774. return false;
  775. }
  776. Types.PgEmitAggApply = (name == "PgEmitAggApply");
  777. }
  778. else if (name == "CostBasedOptimizer") {
  779. if (args.size() != 1) {
  780. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  781. return false;
  782. }
  783. if (!TryFromString(args[0], Types.CostBasedOptimizer)) {
  784. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected `disable|pg|native', but got: " << args[0]));
  785. return false;
  786. }
  787. }
  788. else if (name == "_EnableMatchRecognize" || name == "DisableMatchRecognize") {
  789. if (args.size() != 0) {
  790. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  791. return false;
  792. }
  793. Types.MatchRecognize = name == "_EnableMatchRecognize";
  794. }
  795. else if (name == "TimeOrderRecoverDelay") {
  796. if (args.size() != 1) {
  797. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected one argument, but got " << args.size()));
  798. return false;
  799. }
  800. if (!TryFromString(args[0], Types.TimeOrderRecoverDelay)) {
  801. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  802. return false;
  803. }
  804. if (Types.TimeOrderRecoverDelay >= 0) {
  805. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected negative value, but got: " << args[0]));
  806. return false;
  807. }
  808. }
  809. else if (name == "TimeOrderRecoverAhead") {
  810. if (args.size() != 1) {
  811. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected one argument, but got " << args.size()));
  812. return false;
  813. }
  814. if (!TryFromString(args[0], Types.TimeOrderRecoverAhead)) {
  815. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  816. return false;
  817. }
  818. if (Types.TimeOrderRecoverAhead <= 0) {
  819. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected positive value, but got: " << args[0]));
  820. return false;
  821. }
  822. }
  823. else if (name == "TimeOrderRecoverRowLimit") {
  824. if (args.size() != 1) {
  825. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected one argument, but got " << args.size()));
  826. return false;
  827. }
  828. if (!TryFromString(args[0], Types.TimeOrderRecoverRowLimit)) {
  829. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected integer, but got: " << args[0]));
  830. return false;
  831. }
  832. if (Types.TimeOrderRecoverRowLimit == 0) {
  833. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected positive value, but got: " << args[0]));
  834. return false;
  835. }
  836. }
  837. else if (name == "MatchRecognizeStream") {
  838. if (args.size() != 1) {
  839. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  840. return false;
  841. }
  842. const auto& arg = args[0];
  843. if (arg == "disable") {
  844. Types.MatchRecognizeStreaming = EMatchRecognizeStreamingMode::Disable;
  845. } else if (arg == "auto") {
  846. Types.MatchRecognizeStreaming = EMatchRecognizeStreamingMode::Auto;
  847. } else if (arg == "force") {
  848. Types.MatchRecognizeStreaming = EMatchRecognizeStreamingMode::Force;
  849. } else {
  850. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected `disable|auto|force', but got: " << args[0]));
  851. return false;
  852. }
  853. }
  854. else if (name == "BlockEngine") {
  855. if (args.size() != 1) {
  856. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  857. return false;
  858. }
  859. auto arg = TString{args[0]};
  860. if (!TryFromString(arg, Types.BlockEngineMode)) {
  861. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected `disable|auto|force', but got: " << args[0]));
  862. return false;
  863. }
  864. }
  865. else if (name == "OptimizerFlags") {
  866. for (auto& arg : args) {
  867. if (arg.empty()) {
  868. ctx.AddError(TIssue(pos, "Empty flags are not supported"));
  869. return false;
  870. }
  871. Types.OptimizerFlags.insert(to_lower(ToString(arg)));
  872. }
  873. }
  874. else if (name == "PeepholeFlags") {
  875. for (auto& arg : args) {
  876. if (arg.empty()) {
  877. ctx.AddError(TIssue(pos, "Empty flags are not supported"));
  878. return false;
  879. }
  880. Types.PeepholeFlags.insert(to_lower(ToString(arg)));
  881. }
  882. }
  883. else if (name == "_EnableStreamLookupJoin" || name == "DisableStreamLookupJoin") {
  884. if (args.size() != 0) {
  885. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected no arguments, but got " << args.size()));
  886. return false;
  887. }
  888. Types.StreamLookupJoin = name == "_EnableStreamLookupJoin";
  889. } else if (name == "MaxAggPushdownPredicates") {
  890. if (args.size() != 1) {
  891. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected single numeric argument, but got " << args.size()));
  892. return false;
  893. }
  894. ui32 value;
  895. if (!TryFromString(args[0], value)) {
  896. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected non-negative integer, but got: " << args[0]));
  897. return false;
  898. }
  899. const ui32 hardLimit = 10;
  900. if (value > hardLimit) {
  901. ctx.AddError(TIssue(pos, TStringBuilder() << "Hard limit for setting MaxAggPushdownPredicates is " << hardLimit << ", but got: " << args[0]));
  902. return false;
  903. }
  904. Types.MaxAggPushdownPredicates = value;
  905. } else if (name == "Engine") {
  906. if (args.size() != 1) {
  907. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected at most 1 argument, but got " << args.size()));
  908. return false;
  909. }
  910. auto arg = TString{args[0]};
  911. if (arg == "ytflow") {
  912. if (Types.ForceDq) {
  913. ctx.AddError(TIssue(pos, TStringBuilder()
  914. << "Expected `disable|auto` argument for DqEngine pragma "
  915. << "with Engine pragma argument `ytflow`"));
  916. return false;
  917. }
  918. if (Types.PureResultDataSource == DqProviderName) {
  919. Types.PureResultDataSource.clear();
  920. }
  921. Types.EngineType = EEngineType::Ytflow;
  922. } else if (arg == "dq") {
  923. if (Find(Types.AvailablePureResultDataSources, DqProviderName) == Types.AvailablePureResultDataSources.end()) {
  924. ; // reserved
  925. } else {
  926. Types.PureResultDataSource = DqProviderName;
  927. Types.ForceDq = true;
  928. }
  929. Types.EngineType = EEngineType::Dq;
  930. } else if (arg == "default") {
  931. Types.EngineType = EEngineType::Default;
  932. } else {
  933. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected `default|dq|ytflow', but got: " << arg));
  934. return false;
  935. }
  936. } else {
  937. ctx.AddError(TIssue(pos, TStringBuilder() << "Unsupported command: " << name));
  938. return false;
  939. }
  940. return true;
  941. }
  942. bool ImportUdfs(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  943. if (args.size() != 1 && args.size() != 2) {
  944. ctx.AddError(TIssue(pos, TStringBuilder()
  945. << "Expected 1 or 2 arguments, but got " << args.size()));
  946. return false;
  947. }
  948. if (Types.DisableNativeUdfSupport) {
  949. ctx.AddError(TIssue(pos, "Native UDF support is disabled"));
  950. return false;
  951. }
  952. // file alias
  953. const auto& fileAlias = args[0];
  954. TString customUdfPrefix = args.size() > 1 ? TString(args[1]) : "";
  955. const auto key = TUserDataStorage::ComposeUserDataKey(fileAlias);
  956. TString errorMessage;
  957. const TUserDataBlock* udfSource = Types.UserDataStorage->FreezeUdfNoThrow(key,
  958. errorMessage,
  959. customUdfPrefix);
  960. if (!udfSource) {
  961. ctx.AddError(TIssue(pos, TStringBuilder() << "Unknown file: " << fileAlias << ", details: " << errorMessage));
  962. return false;
  963. }
  964. IUdfResolver::TImport import;
  965. import.Pos = pos;
  966. import.FileAlias = fileAlias;
  967. import.Block = udfSource;
  968. Types.UdfImports.insert({ TString(fileAlias), import });
  969. return true;
  970. }
  971. bool AddCredential(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  972. if (args.size() != 4) {
  973. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 4 arguments, but got " << args.size()));
  974. return false;
  975. }
  976. if (Types.Credentials->FindCredential(args[0])) {
  977. return true;
  978. }
  979. Types.Credentials->AddCredential(TString(args[0]), TCredential(TString(args[1]), TString(args[2]), TString(args[3])));
  980. return true;
  981. }
  982. bool AddFileByUrlImpl(const TStringBuf alias, const TStringBuf url, const TStringBuf token, const TPosition pos, TExprContext& ctx) {
  983. if (url.empty()) {
  984. ctx.AddError(TIssue(pos, TStringBuilder() << "Empty URL for file '" << alias << "'."));
  985. return false;
  986. }
  987. auto key = TUserDataStorage::ComposeUserDataKey(alias);
  988. if (Types.UserDataStorage->ContainsUserDataBlock(key)) {
  989. // Don't overwrite.
  990. return true;
  991. }
  992. TUserDataBlock block;
  993. if (Types.QContext.CanRead()) {
  994. block.Type = EUserDataType::RAW_INLINE_DATA;
  995. } else {
  996. block.Type = EUserDataType::URL;
  997. block.Data = url;
  998. if (token) {
  999. block.UrlToken = token;
  1000. }
  1001. }
  1002. Types.UserDataStorage->AddUserDataBlock(key, block);
  1003. return true;
  1004. }
  1005. bool AddFileByUrl(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  1006. if (args.size() < 2 || args.size() > 3) {
  1007. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 2 or 3 arguments, but got " << args.size()));
  1008. return false;
  1009. }
  1010. TStringBuf token = args.size() == 3 ? args[2] : TStringBuf();
  1011. if (token) {
  1012. if (auto cred = Types.Credentials->FindCredential(token)) {
  1013. token = cred->Content;
  1014. } else {
  1015. ctx.AddError(TIssue(pos, TStringBuilder() << "Unknown token name '" << token << "'."));
  1016. return false;
  1017. }
  1018. }
  1019. return AddFileByUrlImpl(args[0], args[1], token, pos, ctx);
  1020. }
  1021. bool SetFileOptionImpl(const TStringBuf alias, const TString& key, const TString& value, const TPosition& pos, TExprContext& ctx) {
  1022. const auto dataKey = TUserDataStorage::ComposeUserDataKey(alias);
  1023. const auto dataBlock = Types.UserDataStorage->FindUserDataBlock(dataKey);
  1024. if (!dataBlock) {
  1025. ctx.AddError(TIssue(pos, TStringBuilder() << "No such file '" << alias << "'"));
  1026. return false;
  1027. }
  1028. dataBlock->Options[key] = value;
  1029. return true;
  1030. }
  1031. bool SetFileOption(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  1032. if (args.size() != 3) {
  1033. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 3 arguments, but got " << args.size()));
  1034. return false;
  1035. }
  1036. return SetFileOptionImpl(args[0], ToString(args[1]), ToString(args[2]), pos, ctx);
  1037. }
  1038. bool SetPackageVersion(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  1039. if (args.size() != 2) {
  1040. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 2 arguments, but got " << args.size()));
  1041. return false;
  1042. }
  1043. ui32 version = 0;
  1044. if (!TryFromString(args[1], version)) {
  1045. ctx.AddError(TIssue(pos, TStringBuilder() << "Unable to parse package version from " << args[1]));
  1046. return false;
  1047. }
  1048. if (!Types.UdfIndexPackageSet || !Types.UdfIndex) {
  1049. ctx.AddError(TIssue(pos, TStringBuilder() << "UdfIndex is not initialized, unable to set version for package " << args[0]));
  1050. return false;
  1051. }
  1052. if (!Types.UdfIndexPackageSet->AddResourceTo(TString(args[0]), version, Types.UdfIndex)) {
  1053. ctx.AddError(TIssue(pos, TStringBuilder() << "Unable set default version to " << version << " for package " << args[0]));
  1054. return false;
  1055. }
  1056. return true;
  1057. }
  1058. bool DoListSandboxFolder(const TStringBuf url, const TStringBuf token, const TPosition& pos, TExprContext& ctx, NJson::TJsonValue& content) {
  1059. TString urlStr(url);
  1060. if (!url.empty() && url.back() != '/') {
  1061. urlStr += "/";
  1062. }
  1063. const THttpURL& httpUrl = ParseURL(urlStr);
  1064. if (httpUrl.GetHost() != "proxy.sandbox.yandex-team.ru") {
  1065. ctx.AddError(TIssue(pos, TStringBuilder() << "Adding folder by URL is currently supported only for proxy.sandbox.yandex-team.ru. Host " << httpUrl.GetHost() << " is not supported"));
  1066. return false;
  1067. }
  1068. THttpHeaders headers;
  1069. headers.AddHeader("Accept", "application/json");
  1070. if (token) {
  1071. headers.AddHeader("Authorization", TString("OAuth ").append(token));
  1072. }
  1073. auto result = Fetch(httpUrl, headers, TDuration::Seconds(30));
  1074. if (!result) {
  1075. ctx.AddError(TIssue(pos, TStringBuilder() << "Failed to fetch " << url << " for building folder"));
  1076. return false;
  1077. }
  1078. if (result->GetRetCode() != 200) {
  1079. ctx.AddError(TIssue(pos, TStringBuilder() << "Failed to fetch " << url << " for building folder (http code: " << result->GetRetCode() << ")"));
  1080. return false;
  1081. }
  1082. if (!NJson::ReadJsonTree(result->GetStream().ReadAll(), &content)) {
  1083. ctx.AddError(TIssue(pos, TStringBuilder() << "Failed to parse json from " << url << " for building folder"));
  1084. return false;
  1085. }
  1086. return true;
  1087. }
  1088. bool ListSandboxFolder(const TStringBuf url, const TStringBuf token, const TPosition& pos, TExprContext& ctx, NJson::TJsonValue& content) {
  1089. try {
  1090. return WithRetry<std::exception>(3, [&]() {
  1091. return DoListSandboxFolder(url, token, pos, ctx, content);
  1092. }, [&](const auto& e, int attempt, int attemptCount) {
  1093. YQL_CLOG(WARN, ProviderConfig) << "Error in loading sandbox folder " << url << ", attempt " << attempt << "/" << attemptCount << ", details: " << e.what();
  1094. });
  1095. } catch (const std::exception& e) {
  1096. ctx.AddError(TIssue(pos, TStringBuilder() << "Failed to load sandbox folder content from " << url << ", details: " << e.what()));
  1097. return false;
  1098. }
  1099. }
  1100. static TString MakeHttps(const TString& url) {
  1101. if (url.StartsWith("http:")) {
  1102. return "https:" + url.substr(5);
  1103. }
  1104. return url;
  1105. }
  1106. bool AddFolderByUrl(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  1107. if (args.size() < 2 || args.size() > 3) {
  1108. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 2 or 3 arguments, but got " << args.size()));
  1109. return false;
  1110. }
  1111. TStringBuf token = args.size() == 3 ? args[2] : TStringBuf();
  1112. if (token) {
  1113. if (auto cred = Types.Credentials->FindCredential(token)) {
  1114. token = cred->Content;
  1115. } else {
  1116. ctx.AddError(TIssue(pos, TStringBuilder() << "Unknown token name '" << token << "' for folder."));
  1117. return false;
  1118. }
  1119. } else if (auto cred = Types.Credentials->FindCredential("default_sandbox")) {
  1120. token = cred->Content;
  1121. }
  1122. std::vector<std::pair<TString, TString>> queue;
  1123. queue.emplace_back(args[0], args[1]);
  1124. size_t count = 0;
  1125. while (!queue.empty()) {
  1126. auto [prefix, url] = queue.back();
  1127. queue.pop_back();
  1128. YQL_CLOG(DEBUG, ProviderConfig) << "Listing sandbox folder " << prefix << ": " << url;
  1129. NJson::TJsonValue content;
  1130. if (!ListSandboxFolder(url, token, pos, ctx, content)) {
  1131. return false;
  1132. }
  1133. for (const auto& file : content.GetMap()) {
  1134. const auto& fileAttrs = file.second.GetMap();
  1135. auto fileUrl = fileAttrs.FindPtr("url");
  1136. if (fileUrl) {
  1137. TString type = "REGULAR";
  1138. if (auto t = fileAttrs.FindPtr("type")) {
  1139. type = t->GetString();
  1140. }
  1141. TStringBuilder alias;
  1142. if (!prefix.empty()) {
  1143. alias << prefix << "/";
  1144. }
  1145. alias << file.first;
  1146. if (type == "REGULAR") {
  1147. if (!AddFileByUrlImpl(alias, TStringBuf(MakeHttps(fileUrl->GetString())), token, pos, ctx)) {
  1148. return false;
  1149. }
  1150. } else if (type == "DIRECTORY") {
  1151. queue.emplace_back(alias, fileUrl->GetString());
  1152. if (++count > Types.FolderSubDirsLimit) {
  1153. ctx.AddError(TIssue(pos, TStringBuilder() << "Sandbox resource has too many subfolders. Limit is " << Types.FolderSubDirsLimit));
  1154. return false;
  1155. }
  1156. } else {
  1157. YQL_CLOG(WARN, ProviderConfig) << "Got unknown sandbox item type: " << type << ", name=" << alias;
  1158. }
  1159. }
  1160. }
  1161. }
  1162. return true;
  1163. }
  1164. bool SetWarningRule(const TPosition& pos, const TVector<TStringBuf>& args, TExprContext& ctx) {
  1165. if (args.size() != 2) {
  1166. ctx.AddError(TIssue(pos, TStringBuilder() << "Expected 2 arguments, but got " << args.size()));
  1167. return false;
  1168. }
  1169. TString codePattern = TString{args[0]};
  1170. TString action = TString{args[1]};
  1171. TWarningRule rule;
  1172. TString parseError;
  1173. auto parseResult = TWarningRule::ParseFrom(codePattern, action, rule, parseError);
  1174. switch (parseResult) {
  1175. case TWarningRule::EParseResult::PARSE_OK:
  1176. ctx.IssueManager.AddWarningRule(rule);
  1177. break;
  1178. case TWarningRule::EParseResult::PARSE_PATTERN_FAIL:
  1179. case TWarningRule::EParseResult::PARSE_ACTION_FAIL:
  1180. ctx.AddError(TIssue(pos, parseError));
  1181. break;
  1182. default:
  1183. YQL_ENSURE(false, "Unknown parse result");
  1184. }
  1185. return parseResult == TWarningRule::EParseResult::PARSE_OK;
  1186. }
  1187. private:
  1188. TTypeAnnotationContext& Types;
  1189. TAutoPtr<IGraphTransformer> TypeAnnotationTransformer;
  1190. TAutoPtr<IGraphTransformer> ConfigurationTransformer;
  1191. TAutoPtr<IGraphTransformer> CallableExecutionTransformer;
  1192. const TYqlCoreConfig* CoreConfig;
  1193. TString Username;
  1194. const TAllowSettingPolicy Policy;
  1195. TOperationStatistics Statistics;
  1196. };
  1197. }
  1198. TIntrusivePtr<IDataProvider> CreateConfigProvider(TTypeAnnotationContext& types, const TGatewaysConfig* config, const TString& username,
  1199. const TAllowSettingPolicy& policy)
  1200. {
  1201. return new TConfigProvider(types, config, username, policy);
  1202. }
  1203. const THashSet<TStringBuf>& ConfigProviderFunctions() {
  1204. return Singleton<TConfigProvider::TFunctions>()->Names;
  1205. }
  1206. }