sql_match_recognize.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. #include "sql_match_recognize.h"
  2. #include "node.h"
  3. #include "sql_expression.h"
  4. #include <yql/essentials/core/sql_types/match_recognize.h>
  5. namespace NSQLTranslationV1 {
  6. TSqlMatchRecognizeClause::TSqlMatchRecognizeClause(TContext& ctx, NSQLTranslation::ESqlMode mode) : TSqlTranslation(ctx, mode) {}
  7. TMatchRecognizeBuilderPtr TSqlMatchRecognizeClause::CreateBuilder(const NSQLv1Generated::TRule_row_pattern_recognition_clause &matchRecognizeClause) {
  8. auto pos = GetPos(matchRecognizeClause.GetToken1());
  9. if (!Ctx.FeatureR010) {
  10. Ctx.Error(pos, TIssuesIds::CORE) << "Unexpected MATCH_RECOGNIZE";
  11. return {};
  12. }
  13. auto [partitionKeySelector, partitionColumns] = ParsePartitionBy(
  14. pos,
  15. matchRecognizeClause.HasBlock3()
  16. ? std::addressof(matchRecognizeClause.GetBlock3().GetRule_window_partition_clause1())
  17. : nullptr
  18. );
  19. auto sortSpecs = ParseOrderBy(
  20. matchRecognizeClause.HasBlock4()
  21. ? std::addressof(matchRecognizeClause.GetBlock4().GetRule_order_by_clause1())
  22. : nullptr
  23. );
  24. if (!sortSpecs) {
  25. return {};
  26. }
  27. auto measures = ParseMeasures(
  28. matchRecognizeClause.HasBlock5()
  29. ? std::addressof(matchRecognizeClause.GetBlock5().GetRule_row_pattern_measures1().GetRule_row_pattern_measure_list2())
  30. : nullptr
  31. );
  32. auto rowsPerMatch = ParseRowsPerMatch(
  33. pos,
  34. matchRecognizeClause.HasBlock6()
  35. ? std::addressof(matchRecognizeClause.GetBlock6().GetRule_row_pattern_rows_per_match1())
  36. : nullptr
  37. );
  38. if (!rowsPerMatch) {
  39. return {};
  40. }
  41. const auto& commonSyntax = matchRecognizeClause.GetRule_row_pattern_common_syntax7();
  42. if (commonSyntax.HasBlock2()) {
  43. const auto& initialOrSeek = commonSyntax.GetBlock2().GetRule_row_pattern_initial_or_seek1();
  44. Ctx.Error(GetPos(initialOrSeek.GetToken1())) << "InitialOrSeek subclause is not allowed in FROM clause";
  45. return {};
  46. }
  47. PatternVarNames.clear();
  48. PatternVars = BuildList(pos);
  49. auto pattern = ParsePattern(pos, commonSyntax.GetRule_row_pattern5(), 0, true);
  50. if (!pattern) {
  51. return {};
  52. }
  53. auto skipTo = ParseAfterMatchSkipTo(
  54. pos,
  55. commonSyntax.HasBlock1()
  56. ? std::addressof(commonSyntax.GetBlock1().GetRule_row_pattern_skip_to3())
  57. : nullptr
  58. );
  59. if (!skipTo) {
  60. return {};
  61. }
  62. auto subset = ParseSubset(
  63. pos,
  64. commonSyntax.HasBlock7()
  65. ? std::addressof(commonSyntax.GetBlock7().GetRule_row_pattern_subset_clause1())
  66. : nullptr
  67. );
  68. if (!subset) {
  69. return {};
  70. }
  71. auto definitions = ParseDefinitions(commonSyntax.GetRule_row_pattern_definition_list9());
  72. for (const auto& [callable, name]: definitions) {
  73. if (!PatternVarNames.contains(name)) {
  74. Ctx.Error(callable->GetPos()) << "ROW PATTERN VARIABLE " << name << " is defined, but not mentioned in the PATTERN";
  75. return {};
  76. }
  77. }
  78. return new TMatchRecognizeBuilder(
  79. pos,
  80. std::move(partitionKeySelector),
  81. std::move(partitionColumns),
  82. std::move(*sortSpecs),
  83. std::move(measures),
  84. std::move(rowsPerMatch),
  85. std::move(skipTo),
  86. std::move(pattern),
  87. std::move(PatternVars),
  88. std::move(*subset),
  89. std::move(definitions)
  90. );
  91. }
  92. std::tuple<TNodePtr, TNodePtr> TSqlMatchRecognizeClause::ParsePartitionBy(TPosition pos, const TRule_window_partition_clause* node) {
  93. auto [partitionKeySelector, partitionColumns] = [&]() -> std::tuple<TNodePtr, TNodePtr> {
  94. auto partitionKeySelector = BuildList(pos);
  95. auto partitionColumns = BuildList(pos);
  96. if (!node) {
  97. return {partitionKeySelector, partitionColumns};
  98. }
  99. TColumnRefScope scope(Ctx, EColumnRefState::Allow);
  100. TVector<TNodePtr> partitionExprs;
  101. if (!NamedExprList(node->GetRule_named_expr_list4(), partitionExprs)) {
  102. return {partitionKeySelector, partitionColumns};
  103. }
  104. for (const auto& p : partitionExprs) {
  105. auto label = p->GetLabel();
  106. if (!label && p->GetColumnName()) {
  107. label = *p->GetColumnName();
  108. }
  109. partitionKeySelector->Add(p);
  110. partitionColumns->Add(BuildQuotedAtom(p->GetPos(), label));
  111. }
  112. return {partitionKeySelector, partitionColumns};
  113. }();
  114. return {
  115. BuildLambda(pos, BuildList(pos, {BuildAtom(pos, "row")}), BuildQuote(pos, std::move(partitionKeySelector))),
  116. BuildQuote(pos, std::move(partitionColumns))
  117. };
  118. }
  119. TMaybe<TVector<TSortSpecificationPtr>> TSqlMatchRecognizeClause::ParseOrderBy(const TRule_order_by_clause* node) {
  120. if (!node) {
  121. return TVector<TSortSpecificationPtr>{};
  122. }
  123. TVector<TSortSpecificationPtr> result;
  124. if (!OrderByClause(*node, result)) {
  125. return {};
  126. }
  127. return result;
  128. }
  129. TNamedFunction TSqlMatchRecognizeClause::ParseOneMeasure(const TRule_row_pattern_measure_definition& node) {
  130. TColumnRefScope scope(Ctx, EColumnRefState::MatchRecognizeMeasures);
  131. auto callable = TSqlExpression(Ctx, Mode).Build(node.GetRule_expr1());
  132. auto measureName = Id(node.GetRule_an_id3(), *this);
  133. // Each measure must be a lambda, that accepts 2 args:
  134. // - List<InputTableColumns + _yql_Classifier, _yql_MatchNumber>
  135. // - Struct that maps row pattern variables to ranges in the queue
  136. return {std::move(callable), std::move(measureName)};
  137. }
  138. TVector<TNamedFunction> TSqlMatchRecognizeClause::ParseMeasures(const TRule_row_pattern_measure_list* node) {
  139. if (!node) {
  140. return {};
  141. }
  142. TVector<TNamedFunction> result{ParseOneMeasure(node->GetRule_row_pattern_measure_definition1())};
  143. for (const auto& m: node->GetBlock2()) {
  144. result.push_back(ParseOneMeasure(m.GetRule_row_pattern_measure_definition2()));
  145. }
  146. return result;
  147. }
  148. TNodePtr TSqlMatchRecognizeClause::ParseRowsPerMatch(TPosition pos, const TRule_row_pattern_rows_per_match* node) {
  149. const auto result = [&]() -> NYql::NMatchRecognize::ERowsPerMatch {
  150. if (!node) {
  151. return NYql::NMatchRecognize::ERowsPerMatch::OneRow;
  152. }
  153. switch (node->GetAltCase()) {
  154. case TRule_row_pattern_rows_per_match::kAltRowPatternRowsPerMatch1: {
  155. const auto& rowsPerMatch = node->GetAlt_row_pattern_rows_per_match1();
  156. pos = GetPos(rowsPerMatch.GetToken1());
  157. return NYql::NMatchRecognize::ERowsPerMatch::OneRow;
  158. }
  159. case TRule_row_pattern_rows_per_match::kAltRowPatternRowsPerMatch2: {
  160. const auto& rowsPerMatch = node->GetAlt_row_pattern_rows_per_match2();
  161. pos = GetPos(rowsPerMatch.GetToken1());
  162. return NYql::NMatchRecognize::ERowsPerMatch::AllRows;
  163. }
  164. case TRule_row_pattern_rows_per_match::ALT_NOT_SET:
  165. Y_ABORT("You should change implementation according to grammar changes");
  166. }
  167. }();
  168. return BuildQuotedAtom(pos, "RowsPerMatch_" + ToString(result));
  169. }
  170. TNodePtr TSqlMatchRecognizeClause::ParseAfterMatchSkipTo(TPosition pos, const TRule_row_pattern_skip_to* node) {
  171. auto skipToPos = pos;
  172. auto varPos = pos;
  173. const auto result = [&]() -> TMaybe<NYql::NMatchRecognize::TAfterMatchSkipTo> {
  174. if (!node) {
  175. return NYql::NMatchRecognize::TAfterMatchSkipTo{NYql::NMatchRecognize::EAfterMatchSkipTo::PastLastRow, ""};
  176. }
  177. switch (node->GetAltCase()) {
  178. case TRule_row_pattern_skip_to::kAltRowPatternSkipTo1: {
  179. const auto& skipTo = node->GetAlt_row_pattern_skip_to1();
  180. skipToPos = GetPos(skipTo.GetToken1());
  181. return NYql::NMatchRecognize::TAfterMatchSkipTo{NYql::NMatchRecognize::EAfterMatchSkipTo::NextRow, ""};
  182. }
  183. case TRule_row_pattern_skip_to::kAltRowPatternSkipTo2: {
  184. const auto& skipTo = node->GetAlt_row_pattern_skip_to2();
  185. skipToPos = GetPos(skipTo.GetToken1());
  186. return NYql::NMatchRecognize::TAfterMatchSkipTo{NYql::NMatchRecognize::EAfterMatchSkipTo::PastLastRow, ""};
  187. }
  188. case TRule_row_pattern_skip_to::kAltRowPatternSkipTo3: {
  189. const auto& skipTo = node->GetAlt_row_pattern_skip_to3();
  190. skipToPos = GetPos(skipTo.GetToken1());
  191. const auto& identifier = skipTo.GetRule_row_pattern_skip_to_variable_name4().GetRule_row_pattern_variable_name1().GetRule_identifier1();
  192. auto var = identifier.GetToken1().GetValue();
  193. varPos = GetPos(identifier.GetToken1());
  194. if (!PatternVarNames.contains(var)) {
  195. Ctx.Error(varPos) << "Unknown pattern variable in AFTER MATCH SKIP TO FIRST";
  196. return {};
  197. }
  198. return NYql::NMatchRecognize::TAfterMatchSkipTo{NYql::NMatchRecognize::EAfterMatchSkipTo::ToFirst, std::move(var)};
  199. }
  200. case TRule_row_pattern_skip_to::kAltRowPatternSkipTo4: {
  201. const auto& skipTo = node->GetAlt_row_pattern_skip_to4();
  202. skipToPos = GetPos(skipTo.GetToken1());
  203. const auto& identifier = skipTo.GetRule_row_pattern_skip_to_variable_name4().GetRule_row_pattern_variable_name1().GetRule_identifier1();
  204. auto var = identifier.GetToken1().GetValue();
  205. varPos = GetPos(identifier.GetToken1());
  206. if (!PatternVarNames.contains(var)) {
  207. Ctx.Error(varPos) << "Unknown pattern variable in AFTER MATCH SKIP TO LAST";
  208. return {};
  209. }
  210. return NYql::NMatchRecognize::TAfterMatchSkipTo{NYql::NMatchRecognize::EAfterMatchSkipTo::ToLast, std::move(var)};
  211. }
  212. case TRule_row_pattern_skip_to::kAltRowPatternSkipTo5: {
  213. const auto& skipTo = node->GetAlt_row_pattern_skip_to5();
  214. skipToPos = GetPos(skipTo.GetToken1());
  215. const auto& identifier = skipTo.GetRule_row_pattern_skip_to_variable_name3().GetRule_row_pattern_variable_name1().GetRule_identifier1();
  216. auto var = identifier.GetToken1().GetValue();
  217. varPos = GetPos(identifier.GetToken1());
  218. if (!PatternVarNames.contains(var)) {
  219. Ctx.Error(varPos) << "Unknown pattern variable in AFTER MATCH SKIP TO";
  220. return {};
  221. }
  222. return NYql::NMatchRecognize::TAfterMatchSkipTo{NYql::NMatchRecognize::EAfterMatchSkipTo::To, std::move(var)};
  223. }
  224. case TRule_row_pattern_skip_to::ALT_NOT_SET:
  225. Y_ABORT("You should change implementation according to grammar changes");
  226. }
  227. }();
  228. if (!result) {
  229. return {};
  230. }
  231. return BuildTuple(pos, {
  232. BuildQuotedAtom(skipToPos, "AfterMatchSkip_" + ToString(result->To)),
  233. BuildQuotedAtom(varPos, std::move(result->Var))
  234. });
  235. }
  236. TNodePtr TSqlMatchRecognizeClause::BuildPatternFactor(TPosition pos, TNodePtr primary, std::tuple<ui64, ui64, bool, bool, bool> quantifier) {
  237. return std::apply([&](const auto& ...args) {
  238. return BuildTuple(pos, {std::move(primary), BuildQuotedAtom(pos, ToString(args))...});
  239. }, quantifier);
  240. }
  241. TNodePtr TSqlMatchRecognizeClause::ParsePatternFactor(TPosition pos, const TRule_row_pattern_factor& node, size_t nestingLevel, bool output) {
  242. if (nestingLevel > MaxPatternNesting) {
  243. Ctx.Error(pos) << "To big nesting level in the pattern";
  244. return {};
  245. }
  246. auto primary = [&]() -> TNodePtr {
  247. const auto& primaryAlt = node.GetRule_row_pattern_primary1();
  248. switch (primaryAlt.GetAltCase()) {
  249. case TRule_row_pattern_primary::kAltRowPatternPrimary1: {
  250. const auto& primary = primaryAlt.GetAlt_row_pattern_primary1();
  251. const auto& identifier = primary.GetRule_row_pattern_primary_variable_name1().GetRule_row_pattern_variable_name1().GetRule_identifier1();
  252. const auto varName = Id(identifier, *this);
  253. const auto var = BuildQuotedAtom(GetPos(identifier.GetToken1()), varName);
  254. if (PatternVarNames.insert(varName).second) {
  255. PatternVars->Add(var);
  256. }
  257. return var;
  258. }
  259. case TRule_row_pattern_primary::kAltRowPatternPrimary2: {
  260. const auto& primary = primaryAlt.GetAlt_row_pattern_primary2();
  261. const auto& token = primary.GetToken1();
  262. const auto varName = token.GetValue();
  263. const auto var = BuildQuotedAtom(GetPos(token), varName);
  264. if (PatternVarNames.insert(varName).second) {
  265. PatternVars->Add(var);
  266. }
  267. return var;
  268. }
  269. case TRule_row_pattern_primary::kAltRowPatternPrimary3: {
  270. const auto& primary = primaryAlt.GetAlt_row_pattern_primary3();
  271. const auto& token = primary.GetToken1();
  272. const auto varName = token.GetValue();
  273. const auto var = BuildQuotedAtom(GetPos(token), varName);
  274. if (PatternVarNames.insert(varName).second) {
  275. PatternVars->Add(var);
  276. }
  277. return var;
  278. }
  279. case TRule_row_pattern_primary::kAltRowPatternPrimary4: {
  280. const auto& primary = primaryAlt.GetAlt_row_pattern_primary4();
  281. return ParsePattern(pos, primary.GetBlock2().GetRule_row_pattern1(), nestingLevel + 1, output);
  282. }
  283. case TRule_row_pattern_primary::kAltRowPatternPrimary5: {
  284. const auto& primary = primaryAlt.GetAlt_row_pattern_primary5();
  285. output = false;
  286. return ParsePattern(pos, primary.GetRule_row_pattern3(), nestingLevel + 1, output);
  287. }
  288. case TRule_row_pattern_primary::kAltRowPatternPrimary6: {
  289. const auto& primary = primaryAlt.GetAlt_row_pattern_primary6();
  290. std::vector<TNodePtr> items{
  291. ParsePattern(pos, primary.GetRule_row_pattern_permute1().GetRule_row_pattern3(), nestingLevel + 1, output)
  292. };
  293. for (const auto& p: primary.GetRule_row_pattern_permute1().GetBlock4()) {
  294. items.push_back(ParsePattern(pos, p.GetRule_row_pattern2(), nestingLevel + 1, output));
  295. }
  296. if (items.size() > MaxPermutedItems) {
  297. Ctx.Error(GetPos(primary.GetRule_row_pattern_permute1().GetToken1())) << "Too many items in permute";
  298. return {};
  299. }
  300. std::vector<size_t> indexes(items.size());
  301. Iota(indexes.begin(), indexes.end(), 0);
  302. std::vector<TNodePtr> result;
  303. do {
  304. std::vector<TNodePtr> term;
  305. term.reserve(items.size());
  306. for (auto index : indexes) {
  307. term.push_back(BuildPatternFactor(pos, items[index], std::tuple{1, 1, true, output, false}));
  308. }
  309. result.push_back(BuildPatternTerm(pos, std::move(term)));
  310. } while (std::next_permutation(indexes.begin(), indexes.end()));
  311. return BuildPattern(pos, std::move(result));
  312. }
  313. case TRule_row_pattern_primary::ALT_NOT_SET:
  314. Y_ABORT("You should change implementation according to grammar changes");
  315. }
  316. }();
  317. if (!primary) {
  318. return {};
  319. }
  320. const auto quantifier = [&]() {
  321. if (!node.HasBlock2()) {
  322. const auto quantity = static_cast<ui64>(1);
  323. return std::tuple{quantity, quantity, true, output, false};
  324. }
  325. const auto& quantifierAlt = node.GetBlock2().GetRule_row_pattern_quantifier1();
  326. switch (quantifierAlt.GetAltCase()) {
  327. case TRule_row_pattern_quantifier::kAltRowPatternQuantifier1: { // *
  328. const auto& quantifier = quantifierAlt.GetAlt_row_pattern_quantifier1();
  329. pos = GetPos(quantifier.GetToken1());
  330. return std::tuple{static_cast<ui64>(0), static_cast<ui64>(Max()), !quantifier.HasBlock2(), output, false};
  331. }
  332. case TRule_row_pattern_quantifier::kAltRowPatternQuantifier2: { // +
  333. const auto& quantifier = quantifierAlt.GetAlt_row_pattern_quantifier2();
  334. pos = GetPos(quantifier.GetToken1());
  335. return std::tuple{static_cast<ui64>(1), static_cast<ui64>(Max()), !quantifier.HasBlock2(), output, false};
  336. }
  337. case TRule_row_pattern_quantifier::kAltRowPatternQuantifier3: { // ?
  338. const auto& quantifier = quantifierAlt.GetAlt_row_pattern_quantifier3();
  339. pos = GetPos(quantifier.GetToken1());
  340. return std::tuple{static_cast<ui64>(0), static_cast<ui64>(1), !quantifier.HasBlock2(), output, false};
  341. }
  342. case TRule_row_pattern_quantifier::kAltRowPatternQuantifier4: { // {n?, m?}
  343. const auto& quantifier = quantifierAlt.GetAlt_row_pattern_quantifier4();
  344. pos = GetPos(quantifier.GetToken1());
  345. return std::tuple{
  346. quantifier.HasBlock2()
  347. ? FromString(quantifier.GetBlock2().GetRule_integer1().GetToken1().GetValue())
  348. : static_cast<ui64>(0),
  349. quantifier.HasBlock4()
  350. ? FromString(quantifier.GetBlock4().GetRule_integer1().GetToken1().GetValue())
  351. : static_cast<ui64>(Max()),
  352. !quantifier.HasBlock6(),
  353. output,
  354. false
  355. };
  356. }
  357. case TRule_row_pattern_quantifier::kAltRowPatternQuantifier5: { // {n}
  358. const auto quantifier = quantifierAlt.GetAlt_row_pattern_quantifier5();
  359. pos = GetPos(quantifier.GetToken1());
  360. const auto quantity = static_cast<ui64>(FromString(quantifier.GetRule_integer2().GetToken1().GetValue()));
  361. return std::tuple{quantity, quantity, true, output, false};
  362. }
  363. case TRule_row_pattern_quantifier::ALT_NOT_SET:
  364. Y_ABORT("You should change implementation according to grammar changes");
  365. }
  366. }();
  367. return BuildPatternFactor(pos, std::move(primary), std::move(quantifier));
  368. }
  369. TNodePtr TSqlMatchRecognizeClause::BuildPatternTerm(TPosition pos, std::vector<TNodePtr> term) {
  370. auto result = BuildList(pos);
  371. for (auto& factor : term) {
  372. if (!factor) {
  373. return {};
  374. }
  375. result->Add(std::move(factor));
  376. }
  377. return BuildQuote(pos, std::move(result));
  378. }
  379. TNodePtr TSqlMatchRecognizeClause::ParsePatternTerm(TPosition pos, const TRule_row_pattern_term& node, size_t nestingLevel, bool output) {
  380. std::vector<TNodePtr> result;
  381. result.reserve(node.GetBlock1().size());
  382. for (const auto& factor: node.GetBlock1()) {
  383. result.push_back(ParsePatternFactor(pos, factor.GetRule_row_pattern_factor1(), nestingLevel, output));
  384. }
  385. return BuildPatternTerm(pos, std::move(result));
  386. }
  387. TNodePtr TSqlMatchRecognizeClause::BuildPattern(TPosition pos, std::vector<TNodePtr> pattern) {
  388. const auto result = BuildList(pos, {BuildAtom(pos, "MatchRecognizePattern")});
  389. for (auto& term: pattern) {
  390. if (!term) {
  391. return {};
  392. }
  393. result->Add(std::move(term));
  394. }
  395. return result;
  396. }
  397. TNodePtr TSqlMatchRecognizeClause::ParsePattern(TPosition pos, const TRule_row_pattern& node, size_t nestingLevel, bool output) {
  398. std::vector<TNodePtr> result;
  399. result.reserve(1 + node.GetBlock2().size());
  400. result.push_back(ParsePatternTerm(pos, node.GetRule_row_pattern_term1(), nestingLevel, output));
  401. for (const auto& term: node.GetBlock2()) {
  402. result.push_back(ParsePatternTerm(pos, term.GetRule_row_pattern_term2(), nestingLevel, output));
  403. }
  404. return BuildPattern(pos, std::move(result));
  405. }
  406. TMaybe<TNodePtr> TSqlMatchRecognizeClause::ParseSubset(TPosition pos, const TRule_row_pattern_subset_clause* node) {
  407. if (!node) {
  408. return TNodePtr{};
  409. }
  410. pos = GetPos(node->GetToken1());
  411. // TODO https://st.yandex-team.ru/YQL-16225
  412. Ctx.Error(pos) << "SUBSET is not implemented yet";
  413. return {};
  414. }
  415. TNamedFunction TSqlMatchRecognizeClause::ParseOneDefinition(const TRule_row_pattern_definition& node) {
  416. const auto& identifier = node.GetRule_row_pattern_definition_variable_name1().GetRule_row_pattern_variable_name1().GetRule_identifier1();
  417. auto defineName = Id(identifier, *this);
  418. TColumnRefScope scope(Ctx, EColumnRefState::MatchRecognizeDefine, true, defineName);
  419. const auto& searchCondition = node.GetRule_row_pattern_definition_search_condition3().GetRule_search_condition1().GetRule_expr1();
  420. auto callable = TSqlExpression(Ctx, Mode).Build(searchCondition);
  421. // Each define must be a predicate lambda, that accepts 3 args:
  422. // - List<input table rows>
  423. // - A struct that maps row pattern variables to ranges in the queue
  424. // - An index of the current row
  425. return {std::move(callable), std::move(defineName)};
  426. }
  427. TVector<TNamedFunction> TSqlMatchRecognizeClause::ParseDefinitions(const TRule_row_pattern_definition_list& node) {
  428. TVector<TNamedFunction> result{ParseOneDefinition(node.GetRule_row_pattern_definition1())};
  429. for (const auto& d: node.GetBlock2()) {
  430. result.push_back(ParseOneDefinition(d.GetRule_row_pattern_definition2()));
  431. }
  432. return result;
  433. }
  434. } // namespace NSQLTranslationV1