yql_expr_csee.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. #include "yql_expr_csee.h"
  2. #include "yql_expr_type_annotation.h"
  3. #include "yql_expr_optimize.h"
  4. #include <yql/essentials/utils/yql_panic.h>
  5. #include <yql/essentials/utils/log/log.h>
  6. #include <util/generic/hash_set.h>
  7. #include <util/system/env.h>
  8. #include <tuple>
  9. namespace NYql {
  10. namespace {
  11. static constexpr bool UseDeterminsticHash = false;
  12. struct TLambdaFrame {
  13. TLambdaFrame(const TExprNode* lambda, const TLambdaFrame* prev)
  14. : Lambda(lambda)
  15. , Prev(prev)
  16. {}
  17. TLambdaFrame() = default;
  18. const TExprNode* Lambda = nullptr;
  19. const TLambdaFrame* Prev = nullptr;
  20. };
  21. bool IsArgInScope(const TLambdaFrame& frame, const TExprNode& arg) {
  22. for (auto curr = &frame; curr; curr = curr->Prev) {
  23. if (const auto lambda = curr->Lambda) {
  24. YQL_ENSURE(lambda->IsLambda());
  25. for (ui32 i = 0U; i < lambda->Head().ChildrenSize(); ++i) {
  26. if (lambda->Head().Child(i) == &arg) {
  27. return true;
  28. }
  29. }
  30. }
  31. }
  32. return false;
  33. }
  34. ui16 GetDependencyLevel(const TExprNode& node) {
  35. if (const auto lambda = node.GetDependencyScope()->first) {
  36. return 1 + GetDependencyLevel(*lambda);
  37. }
  38. return 0;
  39. }
  40. enum class EDependencyScope : ui8 {
  41. None = 0,
  42. Inner = 1,
  43. Outer = 2,
  44. Mixed = Inner | Outer
  45. };
  46. EDependencyScope CheckDependencyScope(const TLambdaFrame& frame, const TExprNode& node) {
  47. if (!node.IsAtom()) {
  48. if (const auto scope = node.GetDependencyScope()) {
  49. const auto outerLambda = scope->first;
  50. const auto innerLambda = scope->second;
  51. if (bool innerFound = false; innerLambda || outerLambda) {
  52. for (auto curr = &frame; curr; curr = curr->Prev) {
  53. if (!innerFound && innerLambda) {
  54. if (curr->Lambda == innerLambda) {
  55. innerFound = true;
  56. } else {
  57. continue;
  58. }
  59. }
  60. if (curr->Lambda == outerLambda) {
  61. return curr->Lambda == &node ? EDependencyScope::None : EDependencyScope::Inner;
  62. }
  63. }
  64. return innerFound ? EDependencyScope::Mixed : EDependencyScope::Outer;
  65. }
  66. }
  67. }
  68. return EDependencyScope::None;
  69. }
  70. ui64 CalculateHash(ui16 depth, TExprNode& node, const TLambdaFrame& currFrame, const TColumnOrderStorage& coStore) {
  71. const auto dependency = CheckDependencyScope(currFrame, node);
  72. switch (dependency) {
  73. case EDependencyScope::None:
  74. if (const auto hash = node.GetHash()) {
  75. return hash;
  76. }
  77. break;
  78. case EDependencyScope::Inner:
  79. if (const auto hash = node.GetHashAbove()) {
  80. return hash;
  81. }
  82. break;
  83. case EDependencyScope::Outer:
  84. if (const auto hash = node.GetHashBelow()) {
  85. return hash;
  86. }
  87. break;
  88. case EDependencyScope::Mixed:
  89. break;
  90. }
  91. ui64 hash = node.GetTypeAnn()->GetHash();
  92. hash = CseeHash(ui32(node.Type()), hash);
  93. for (auto c: node.GetAllConstraints()) {
  94. hash = CseeHash(c->GetHash(), hash);
  95. }
  96. hash = AddColumnOrderHash(coStore.Lookup(node.UniqueId()), hash);
  97. switch (node.Type()) {
  98. case TExprNode::Atom: {
  99. if constexpr (UseDeterminsticHash) {
  100. hash = CseeHash(node.Content().data(), node.Content().size(), hash);
  101. } else {
  102. // can hash ptr due to intern
  103. const char* ptr = node.Content().data();
  104. hash = CseeHash(&ptr, sizeof(ptr), hash);
  105. }
  106. hash = CseeHash(node.GetFlagsToCompare(), hash);
  107. break;
  108. }
  109. case TExprNode::Callable:
  110. if constexpr (UseDeterminsticHash) {
  111. hash = CseeHash(node.Content().data(), node.Content().size(), hash);
  112. } else {
  113. // can hash ptr due to intern
  114. const char* ptr = node.Content().data();
  115. hash = CseeHash(&ptr, sizeof(ptr), hash);
  116. }
  117. [[fallthrough]];
  118. case TExprNode::List: {
  119. const auto size = node.ChildrenSize();
  120. hash = CseeHash(size, hash);
  121. if (node.UnorderedChildren()) {
  122. TSmallVec<ui64> hashes;
  123. hashes.reserve(size);
  124. for (ui32 i = 0U; i < node.ChildrenSize(); ++i) {
  125. hashes.emplace_back(CalculateHash(depth, *node.Child(i), currFrame, coStore));
  126. };
  127. std::sort(hashes.begin(), hashes.end());
  128. hash = std::accumulate(hashes.cbegin(), hashes.cend(), ~hash, [] (ui64 hash, ui64 childHash) {
  129. return CseeHash(childHash, hash);
  130. });
  131. } else {
  132. for (ui32 i = 0U; i < node.ChildrenSize(); ++i) {
  133. const auto childHash = CalculateHash(depth, *node.Child(i), currFrame, coStore);
  134. hash = CseeHash(childHash, hash);
  135. }
  136. }
  137. break;
  138. }
  139. case TExprNode::Lambda: {
  140. if (const ui32 size = node.ChildrenSize())
  141. hash = CseeHash(size, hash);
  142. const auto& args = node.Head();
  143. hash = CseeHash(args.ChildrenSize(), hash);
  144. for (ui32 i = 0; i < args.ChildrenSize(); ++i) {
  145. const auto& arg = *args.Child(i);
  146. hash = CseeHash(arg.GetTypeAnn()->GetHash(), hash);
  147. for (auto c: arg.GetAllConstraints()) {
  148. hash = CseeHash(c->GetHash(), hash);
  149. }
  150. }
  151. TLambdaFrame newFrame(&node, &currFrame);
  152. for (ui32 i = 1U; i < node.ChildrenSize(); ++i) {
  153. const auto lambdaHash = CalculateHash(depth + 1, *node.Child(i), newFrame, coStore);
  154. hash = CseeHash(lambdaHash, hash);
  155. }
  156. break;
  157. }
  158. case TExprNode::Argument:
  159. switch (dependency) {
  160. case EDependencyScope::Inner: {
  161. hash = CseeHash(GetDependencyLevel(node), hash);
  162. hash = CseeHash(node.GetArgIndex(), hash);
  163. break;
  164. }
  165. case EDependencyScope::Outer: {
  166. if constexpr (UseDeterminsticHash) {
  167. hash = CseeHash(node.UniqueId(), hash);
  168. } else {
  169. const auto ptr = &node;
  170. hash = CseeHash(&ptr, sizeof(ptr), hash);
  171. }
  172. break;
  173. }
  174. case EDependencyScope::None:
  175. case EDependencyScope::Mixed:
  176. Y_ABORT("Strange argument.");
  177. }
  178. break;
  179. case TExprNode::World:
  180. break;
  181. default:
  182. YQL_ENSURE(false, "Unexpected");
  183. }
  184. if (hash == 0) {
  185. hash = 1;
  186. }
  187. switch (dependency) {
  188. case EDependencyScope::None:
  189. node.SetHash(hash);
  190. break;
  191. case EDependencyScope::Inner:
  192. node.SetHashAbove(hash);
  193. break;
  194. case EDependencyScope::Outer:
  195. node.SetHashBelow(hash);
  196. break;
  197. case EDependencyScope::Mixed:
  198. break;
  199. }
  200. return hash;
  201. }
  202. using TEqualResults = THashMap<std::pair<const TExprNode*, const TExprNode*>, bool>;
  203. bool DoEqualNodes(const TExprNode& left, TLambdaFrame& currLeftFrame, const TExprNode& right, TLambdaFrame& currRightFrame,
  204. TEqualResults& visited, const TColumnOrderStorage& coStore);
  205. bool EqualNodes(const TExprNode& left, TLambdaFrame& currLeftFrame, const TExprNode& right, TLambdaFrame& currRightFrame,
  206. TEqualResults& visited, const TColumnOrderStorage& coStore)
  207. {
  208. if (&left == &right) {
  209. return true;
  210. }
  211. auto key = std::make_pair(&left, &right);
  212. if (auto it = visited.find(key); it != visited.end()) {
  213. return it->second;
  214. }
  215. bool res = DoEqualNodes(left, currLeftFrame, right, currRightFrame, visited, coStore);
  216. visited[key] = res;
  217. return res;
  218. }
  219. bool DoEqualNodes(const TExprNode& left, TLambdaFrame& currLeftFrame, const TExprNode& right, TLambdaFrame& currRightFrame,
  220. TEqualResults& visited, const TColumnOrderStorage& coStore)
  221. {
  222. if (left.Type() != right.Type()) {
  223. return false;
  224. }
  225. if (left.GetTypeAnn() != right.GetTypeAnn()) {
  226. return false;
  227. }
  228. if (left.GetAllConstraints() != right.GetAllConstraints()) {
  229. return false;
  230. }
  231. auto l = coStore.Lookup(left.UniqueId());
  232. auto r = coStore.Lookup(right.UniqueId());
  233. if (l && r && *l != *r) {
  234. return false;
  235. }
  236. switch (left.Type()) {
  237. case TExprNode::Atom:
  238. // compare pointers due to intern
  239. return left.Content().data() == right.Content().data() && left.GetFlagsToCompare() == right.GetFlagsToCompare();
  240. case TExprNode::Callable:
  241. // compare pointers due to intern
  242. if (left.Content().data() != right.Content().data()) {
  243. return false;
  244. }
  245. [[fallthrough]];
  246. case TExprNode::List:
  247. if (left.ChildrenSize() != right.ChildrenSize()) {
  248. return false;
  249. }
  250. if (left.UnorderedChildren() && right.UnorderedChildren()) {
  251. if (2U == left.ChildrenSize()) {
  252. return EqualNodes(left.Head(), currLeftFrame, right.Head(), currRightFrame, visited, coStore)
  253. && EqualNodes(left.Tail(), currLeftFrame, right.Tail(), currRightFrame, visited, coStore)
  254. || EqualNodes(left.Head(), currLeftFrame, right.Tail(), currRightFrame, visited, coStore)
  255. && EqualNodes(left.Tail(), currLeftFrame, right.Head(), currRightFrame, visited, coStore);
  256. } else {
  257. TSmallVec<const TExprNode*> lNodes, rNodes;
  258. lNodes.reserve(left.ChildrenSize());
  259. rNodes.reserve(right.ChildrenSize());
  260. left.ForEachChild([&lNodes](const TExprNode& child){ return lNodes.emplace_back(&child); });
  261. right.ForEachChild([&rNodes](const TExprNode& child){ return rNodes.emplace_back(&child); });
  262. const auto order = [](const TExprNode* l, const TExprNode* r) { return l->GetHashAbove() < r->GetHashAbove(); };
  263. std::sort(lNodes.begin(), lNodes.end(), order);
  264. std::sort(rNodes.begin(), rNodes.end(), order);
  265. for (ui32 i = 0; i < lNodes.size(); ++i) {
  266. if (!EqualNodes(*lNodes[i], currLeftFrame, *rNodes[i], currRightFrame, visited, coStore)) {
  267. return false;
  268. }
  269. }
  270. }
  271. } else {
  272. for (ui32 i = 0; i < left.ChildrenSize(); ++i) {
  273. if (!EqualNodes(*left.Child(i), currLeftFrame, *right.Child(i), currRightFrame, visited, coStore)) {
  274. return false;
  275. }
  276. }
  277. }
  278. return true;
  279. case TExprNode::Lambda: {
  280. if (left.IsComplete() != right.IsComplete()) {
  281. return false;
  282. }
  283. if (left.ChildrenSize() != right.ChildrenSize()) {
  284. return false;
  285. }
  286. const auto& leftArgs = left.Head();
  287. const auto& rightArgs = right.Head();
  288. if (leftArgs.ChildrenSize() != rightArgs.ChildrenSize()) {
  289. return false;
  290. }
  291. for (ui32 i = 0; i < leftArgs.ChildrenSize(); ++i) {
  292. const auto& leftArg = *leftArgs.Child(i);
  293. const auto& rightArg = *rightArgs.Child(i);
  294. if (leftArg.GetTypeAnn() != rightArg.GetTypeAnn()) {
  295. return false;
  296. }
  297. if (leftArg.GetAllConstraints() != rightArg.GetAllConstraints()) {
  298. return false;
  299. }
  300. }
  301. TLambdaFrame newLeftFrame(&left, &currLeftFrame);
  302. TLambdaFrame newRightFrame(&right, &currRightFrame);
  303. for (ui32 i = 1U; i < left.ChildrenSize(); ++i) {
  304. if (!EqualNodes(*left.Child(i), newLeftFrame, *right.Child(i), newRightFrame, visited, coStore))
  305. return false;
  306. }
  307. return true;
  308. }
  309. case TExprNode::Argument: {
  310. if (currLeftFrame.Lambda && currRightFrame.Lambda && IsArgInScope(currLeftFrame, left) && IsArgInScope(currRightFrame, right)) {
  311. const ui16 leftRelativeLevel = GetDependencyLevel(left);
  312. const ui16 rightRelativeLevel = GetDependencyLevel(right);
  313. return leftRelativeLevel == rightRelativeLevel && left.GetArgIndex() == right.GetArgIndex();
  314. } else {
  315. return &left == &right;
  316. }
  317. }
  318. case TExprNode::Arguments:
  319. break;
  320. case TExprNode::World:
  321. return true;
  322. }
  323. YQL_ENSURE(false, "Unexpected");
  324. return false;
  325. }
  326. using TCompareResults = THashMap<std::pair<const TExprNode*, const TExprNode*>, int>;
  327. int DoCompareNodes(const TExprNode& left, const TExprNode& right, TCompareResults& visited);
  328. int CompareNodes(const TExprNode& left, const TExprNode& right, TCompareResults& visited) {
  329. if (&left == &right) {
  330. return 0;
  331. }
  332. auto key = std::make_pair(&left, &right);
  333. if (auto it = visited.find(key); it != visited.end()) {
  334. return it->second;
  335. }
  336. int res = DoCompareNodes(left, right, visited);
  337. visited[key] = res;
  338. return res;
  339. }
  340. int DoCompareNodes(const TExprNode& left, const TExprNode& right, TCompareResults& visited) {
  341. if (left.Type() != right.Type()) {
  342. return (int)left.Type() - (int)right.Type();
  343. }
  344. switch (left.Type()) {
  345. case TExprNode::Atom:
  346. if (left.Content().size() != right.Content().size()) {
  347. return (int)left.Content().size() - (int)right.Content().size();
  348. }
  349. // compare pointers due to intern
  350. if (left.Content().data() != right.Content().data()) {
  351. if (const auto res = left.Content().compare(right.Content())) {
  352. return res;
  353. }
  354. }
  355. return (int)left.GetFlagsToCompare() - (int)right.GetFlagsToCompare();
  356. case TExprNode::Callable:
  357. if (left.Content().size() != right.Content().size()) {
  358. return (int)left.Content().size() - (int)right.Content().size();
  359. }
  360. // compare pointers due to intern
  361. if (left.Content().data() != right.Content().data()) {
  362. if (const auto res = left.Content().compare(right.Content())) {
  363. return res;
  364. }
  365. }
  366. [[fallthrough]];
  367. case TExprNode::List:
  368. if (left.ChildrenSize() != right.ChildrenSize()) {
  369. return (int)left.ChildrenSize() - (int)right.ChildrenSize();
  370. }
  371. for (ui32 i = 0; i < left.ChildrenSize(); ++i) {
  372. if (const auto res = CompareNodes(*left.Child(i), *right.Child(i), visited)) {
  373. return res;
  374. }
  375. }
  376. return 0;
  377. case TExprNode::Lambda: {
  378. if (left.ChildrenSize() != right.ChildrenSize()) {
  379. return (int)left.ChildrenSize() - (int)right.ChildrenSize();
  380. }
  381. const auto& leftArgs = left.Head();
  382. const auto& rightArgs = right.Head();
  383. if (leftArgs.ChildrenSize() != rightArgs.ChildrenSize()) {
  384. return (int)leftArgs.ChildrenSize() - (int)rightArgs.ChildrenSize();
  385. }
  386. for (ui32 i = 1U; i < left.ChildrenSize(); ++i) {
  387. if (const auto c = CompareNodes(*left.Child(i), *right.Child(i), visited))
  388. return c;
  389. }
  390. return 0;
  391. }
  392. case TExprNode::Argument:
  393. if (left.GetArgIndex() != right.GetArgIndex()) {
  394. return (int)left.GetArgIndex() - (int)right.GetArgIndex();
  395. }
  396. return (int)left.GetDependencyScope()->first->GetLambdaLevel() - (int)right.GetDependencyScope()->first->GetLambdaLevel();
  397. case TExprNode::Arguments:
  398. break;
  399. case TExprNode::World:
  400. return 0;
  401. }
  402. YQL_ENSURE(false, "Unexpected");
  403. return 0;
  404. }
  405. void CalculateCompletness(TExprNode& node, bool insideDependsOn, ui16 level, TNodeSet& closures,
  406. TNodeMap<TNodeSet>& visited, TNodeMap<TNodeSet>& visitedInsideDependsOn) {
  407. switch (node.Type()) {
  408. case TExprNode::Atom:
  409. node.SetDependencyScope(nullptr, nullptr);
  410. return;
  411. case TExprNode::Argument:
  412. closures.emplace(node.GetDependencyScope()->first);
  413. if (insideDependsOn) {
  414. node.SetUsedInDependsOn();
  415. }
  416. return;
  417. default: break;
  418. }
  419. const auto ins = (insideDependsOn ? visitedInsideDependsOn : visited).emplace(&node, TNodeSet{});
  420. if (!ins.second) {
  421. closures.insert(ins.first->second.cbegin(), ins.first->second.cend());
  422. return;
  423. }
  424. auto& internal = ins.first->second;
  425. if (TExprNode::Lambda == node.Type()) {
  426. node.SetLambdaLevel(level);
  427. node.Head().ForEachChild(std::bind(&TExprNode::SetDependencyScope, std::placeholders::_1, &node, &node));
  428. for (ui32 i = 1U; i < node.ChildrenSize(); ++i) {
  429. CalculateCompletness(*node.Child(i), insideDependsOn, level + 1, internal, visited, visitedInsideDependsOn);
  430. }
  431. internal.erase(&node);
  432. } else {
  433. insideDependsOn = insideDependsOn || node.IsCallable("DependsOn");
  434. node.ForEachChild(std::bind(&CalculateCompletness, std::placeholders::_1, insideDependsOn, level, std::ref(internal),
  435. std::ref(visited), std::ref(visitedInsideDependsOn)));
  436. }
  437. const TExprNode* outerLambda = nullptr;
  438. const TExprNode* innerLambda = nullptr;
  439. for (const auto lambda : internal) {
  440. if (!outerLambda || lambda->GetLambdaLevel() < outerLambda->GetLambdaLevel()) {
  441. outerLambda = lambda;
  442. }
  443. if (!innerLambda || lambda->GetLambdaLevel() > innerLambda->GetLambdaLevel()) {
  444. innerLambda = lambda;
  445. }
  446. }
  447. node.SetDependencyScope(outerLambda, innerLambda);
  448. closures.insert(internal.cbegin(), internal.cend());
  449. }
  450. ui64 CalcHash(TExprNode& node, const TColumnOrderStorage& coStore) {
  451. TLambdaFrame frame;
  452. return CalculateHash(0, node, frame, coStore);
  453. }
  454. bool EqualNodes(const TExprNode& left, const TExprNode& right, const TColumnOrderStorage& coStore) {
  455. TEqualResults visited;
  456. TLambdaFrame frame;
  457. return EqualNodes(left, frame, right, frame, visited, coStore);
  458. }
  459. TExprNode::TPtr VisitNode(TExprNode& node, TExprNode* currentLambda, ui16 level,
  460. std::unordered_multimap<ui64, TExprNode*>& uniqueNodes,
  461. std::unordered_multimap<ui64, TExprNode*>& incompleteNodes,
  462. TNodeMap<TExprNode*>& renames, const TColumnOrderStorage& coStore,
  463. const TNodeSet& reachable) {
  464. if (node.Type() == TExprNode::Argument) {
  465. return nullptr;
  466. }
  467. const auto find = renames.emplace(&node, nullptr);
  468. if (!find.second) {
  469. return find.first->second;
  470. }
  471. const auto hash = CalcHash(node, coStore);
  472. if (node.Type() == TExprNode::Lambda) {
  473. for (ui32 i = 1U; i < node.ChildrenSize(); ++i) {
  474. if (auto newNode = VisitNode(*node.Child(i), &node, level + 1U, uniqueNodes, incompleteNodes, renames, coStore, reachable)) {
  475. node.ChildRef(i) = std::move(newNode);
  476. }
  477. }
  478. } else {
  479. for (ui32 i = 0; i < node.ChildrenSize(); ++i) {
  480. if (auto newNode = VisitNode(*node.Child(i), currentLambda, level, uniqueNodes, incompleteNodes, renames, coStore, reachable)) {
  481. node.ChildRef(i) = std::move(newNode);
  482. }
  483. }
  484. }
  485. if (const auto kind = node.GetTypeAnn()->GetKind(); ETypeAnnotationKind::Flow != kind && ETypeAnnotationKind::Stream != kind || node.IsLambda()) {
  486. auto& nodesSet = node.IsComplete() ? uniqueNodes : incompleteNodes;
  487. const auto pair = nodesSet.equal_range(hash);
  488. auto iter = pair.first;
  489. while (pair.second != iter) {
  490. // search for duplicates
  491. if (iter->second->Dead()) {
  492. iter = nodesSet.erase(iter);
  493. continue;
  494. }
  495. if (!reachable.contains(iter->second)) {
  496. iter = nodesSet.erase(iter);
  497. continue;
  498. }
  499. if (!EqualNodes(node, *iter->second, coStore)) {
  500. #ifndef NDEBUG
  501. if (!GetEnv("YQL_ALLOW_CSEE_HASH_COLLISION")) {
  502. YQL_ENSURE(false, "Node -BEGIN-\n" << node.Dump() << "-END-" << " has same hash as -BEGIN-\n"
  503. << iter->second->Dump() << "-END-");
  504. }
  505. #endif
  506. ++iter;
  507. continue;
  508. }
  509. if (iter->second == &node)
  510. return nullptr;
  511. find.first->second = iter->second;
  512. if (node.Type() == TExprNode::Atom) {
  513. iter->second->NormalizeAtomFlags(node);
  514. }
  515. return iter->second;
  516. }
  517. nodesSet.emplace_hint(iter, hash, &node);
  518. }
  519. return nullptr;
  520. }
  521. }
  522. IGraphTransformer::TStatus UpdateCompletness(const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext&) {
  523. YQL_PROFILE_SCOPE(DEBUG, "UpdateCompletness");
  524. output = input;
  525. // process closures
  526. TNodeSet closures;
  527. TNodeMap<TNodeSet> visited;
  528. TNodeMap<TNodeSet> visitedInsideDependsOn;
  529. CalculateCompletness(*input, false, 0, closures, visited, visitedInsideDependsOn);
  530. return IGraphTransformer::TStatus::Ok;
  531. }
  532. IGraphTransformer::TStatus EliminateCommonSubExpressions(const TExprNode::TPtr& input, TExprNode::TPtr& output,
  533. TExprContext& ctx, bool forSubGraph, const TColumnOrderStorage& coStore)
  534. {
  535. YQL_PROFILE_SCOPE(DEBUG, forSubGraph ? "EliminateCommonSubExpressionsForSubGraph" : "EliminateCommonSubExpressions");
  536. output = input;
  537. TNodeSet reachable;
  538. VisitExpr(*output, [&](const TExprNode& node) {
  539. reachable.emplace(&node);
  540. return true;
  541. });
  542. TNodeMap<TExprNode*> renames;
  543. //Cerr << "INPUT\n" << output->Dump() << "\n";
  544. std::unordered_multimap<ui64, TExprNode*> incompleteNodes;
  545. const auto newNode = VisitNode(*output, nullptr, 0, ctx.UniqueNodes, incompleteNodes, renames, coStore, reachable);
  546. YQL_ENSURE(forSubGraph || !newNode);
  547. //Cerr << "OUTPUT\n" << output->Dump() << "\n";
  548. return IGraphTransformer::TStatus::Ok;
  549. }
  550. int CompareNodes(const TExprNode& left, const TExprNode& right) {
  551. TCompareResults visited;
  552. return CompareNodes(left, right, visited);
  553. }
  554. }