hqlgraph.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jliball.hpp"
  15. #include "hql.hpp"
  16. #include "platform.h"
  17. #include "jlib.hpp"
  18. #include "jmisc.hpp"
  19. #include "jstream.ipp"
  20. #include "jdebug.hpp"
  21. #include "hql.hpp"
  22. #include "hqlthql.hpp"
  23. #include "hqlhtcpp.ipp"
  24. #include "hqlttcpp.ipp"
  25. #include "hqlutil.hpp"
  26. #include "hqlthql.hpp"
  27. #include "hqlpmap.hpp"
  28. #include "hqlwcpp.hpp"
  29. #include "hqlcpputil.hpp"
  30. #include "hqltcppc.ipp"
  31. #include "hqlopt.hpp"
  32. #include "hqlfold.hpp"
  33. #include "hqlcerrors.hpp"
  34. #include "hqlcatom.hpp"
  35. #include "hqlgraph.ipp"
  36. #include "thorcommon.hpp"
  37. //---------------------------------------------------------------------------
  38. IPropertyTree * addGraphAttribute(IPropertyTree * node, const char * name)
  39. {
  40. IPropertyTree * att = createPTree();
  41. att->setProp("@name", name);
  42. return node->addPropTree("att", att);
  43. }
  44. void addGraphAttribute(IPropertyTree * node, const char * name, const char * value)
  45. {
  46. addGraphAttribute(node, name)->setProp("@value", value);
  47. }
  48. void addGraphAttributeInt(IPropertyTree * node, const char * name, __int64 value)
  49. {
  50. addGraphAttribute(node, name)->setPropInt64("@value", value);
  51. }
  52. void addGraphAttributeBool(IPropertyTree * node, const char * name, bool value)
  53. {
  54. if (value)
  55. addGraphAttribute(node, name)->setPropBool("@value", value);
  56. }
  57. void addSimpleGraphEdge(IPropertyTree * subGraph, unsigned __int64 source, unsigned __int64 target, unsigned outputIndex, unsigned inputIndex, _ATOM kind, const char * label, bool nWay)
  58. {
  59. IPropertyTree *edge = createPTree();
  60. edge->setPropInt64("@target", target);
  61. edge->setPropInt64("@source", source);
  62. if (outputIndex != 0)
  63. addGraphAttributeInt(edge, "_sourceIndex", outputIndex);
  64. if (inputIndex != 0)
  65. addGraphAttributeInt(edge, "_targetIndex", inputIndex);
  66. if (label)
  67. edge->setProp("@label", label);
  68. if (kind == dependencyAtom)
  69. addGraphAttributeBool(edge, "_dependsOn", true);
  70. if (nWay)
  71. edge->setPropBool("@nWay", true);
  72. StringBuffer s;
  73. edge->setProp("@id", s.append(source).append('_').append(outputIndex).str());
  74. subGraph->addPropTree("edge", edge);
  75. }
  76. void addComplexGraphEdge(IPropertyTree * graph, unsigned __int64 sourceGraph, unsigned __int64 targetGraph, unsigned __int64 sourceActivity, unsigned __int64 targetActivity, unsigned outputIndex, _ATOM kind, const char * label)
  77. {
  78. StringBuffer idText;
  79. IPropertyTree *edge = createPTree();
  80. edge->setProp("@id", idText.clear().append(sourceGraph).append('_').append(targetGraph).append("_").append(outputIndex).str());
  81. edge->setPropInt64("@target", sourceGraph);
  82. edge->setPropInt64("@source", targetGraph);
  83. if (label)
  84. edge->setProp("@label", label);
  85. if (outputIndex)
  86. addGraphAttributeInt(edge, "_sourceIndex", outputIndex);
  87. if (kind == dependencyAtom)
  88. addGraphAttributeBool(edge, "_dependsOn", true);
  89. addGraphAttributeInt(edge, "_sourceActivity", sourceActivity);
  90. addGraphAttributeInt(edge, "_targetActivity", targetActivity);
  91. graph->addPropTree("edge", edge);
  92. }
  93. void removeGraphAttribute(IPropertyTree * node, const char * name)
  94. {
  95. StringBuffer xpath;
  96. xpath.append("att[@name=\"").append(name).append("\"]");
  97. node->removeProp(xpath.str());
  98. }
  99. static void queryExpandFilename(StringBuffer & out, IHqlExpression * expr)
  100. {
  101. if (expr)
  102. {
  103. OwnedHqlExpr folded = foldHqlExpression(expr);
  104. if (folded->queryValue())
  105. folded->queryValue()->generateECL(out.append('\n'));
  106. }
  107. }
  108. //---------------------------------------------------------------------------
  109. static void addDependent(HqlExprArray & dependents, IHqlExpression * expr)
  110. {
  111. if (dependents.find(*expr) == NotFound)
  112. dependents.append(*LINK(expr));
  113. }
  114. LogicalGraphCreator::LogicalGraphCreator(IWorkUnit * _wu)
  115. {
  116. lockTransformMutex();
  117. seq = 0;
  118. wu = _wu;
  119. expandPersist = wu->getDebugValueBool("logicalGraphExpandPersist", true);
  120. expandStored = wu->getDebugValueBool("logicalGraphExpandStored", false);
  121. includeNameInText = wu->getDebugValueBool("logicalGraphIncludeName", true);
  122. includeModuleInText = wu->getDebugValueBool("logicalGraphIncludeModule", true);
  123. displayJavadoc = wu->getDebugValueBool("logicalGraphDisplayJavadoc", true);
  124. displayJavadocParameters = wu->getDebugValueBool("logicalGraphDisplayJavadocParameters", false);
  125. rootGraphId = 0;
  126. subGraphId = 0;
  127. }
  128. LogicalGraphCreator::~LogicalGraphCreator()
  129. {
  130. unlockTransformMutex();
  131. }
  132. void LogicalGraphCreator::addAttribute(const char * name, const char * value)
  133. {
  134. addGraphAttribute(activityNode, name, value);
  135. }
  136. void LogicalGraphCreator::addAttribute(const char * name, _ATOM value)
  137. {
  138. if (value)
  139. addGraphAttribute(activityNode, name, value->str());
  140. }
  141. void LogicalGraphCreator::addAttributeInt(const char * name, __int64 value)
  142. {
  143. addGraphAttributeInt(activityNode, name, value);
  144. }
  145. void LogicalGraphCreator::addAttributeBool(const char * name, bool value)
  146. {
  147. addGraphAttributeBool(activityNode, name, value);
  148. }
  149. void LogicalGraphCreator::beginActivity(const char * label, unique_id_t id)
  150. {
  151. activityNode.set(curSubGraph()->addPropTree("node", createPTree()));
  152. if (label)
  153. activityNode->setProp("@label", label);
  154. activityNode->setPropInt64("@id", id);
  155. }
  156. void LogicalGraphCreator::beginSubGraph(const char * label, bool nested)
  157. {
  158. savedGraphId.append(subGraphId);
  159. if (!nested)
  160. saveSubGraphs();
  161. if ((subGraphs.ordinality() == 0) && rootSubGraph)
  162. {
  163. subGraphs.append(*LINK(rootSubGraph));
  164. subGraphId = rootGraphId;
  165. return;
  166. }
  167. subGraphId = ++seq;
  168. IPropertyTree * node = createPTree("node");
  169. node = curSubGraph()->addPropTree("node", node);
  170. node->setPropInt64("@id", subGraphId);
  171. IPropertyTree * graphAttr = node->addPropTree("att", createPTree("att"));
  172. IPropertyTree * subGraph = graphAttr->addPropTree("graph", createPTree("graph"));
  173. subGraphs.append(*LINK(subGraph));
  174. if (!rootSubGraph)
  175. {
  176. rootSubGraph.set(subGraph);
  177. rootGraphId = subGraphId;
  178. }
  179. }
  180. void LogicalGraphCreator::connectActivities(IHqlExpression * fromExpr, IHqlExpression * toExpr, _ATOM kind, const char * label, bool nWay)
  181. {
  182. StringBuffer tempLabel;
  183. if (fromExpr->getOperator() == no_comma)
  184. {
  185. fromExpr->queryChild(1)->queryValue()->getStringValue(tempLabel);
  186. fromExpr = fromExpr->queryChild(0);
  187. label = tempLabel.str();
  188. }
  189. LogicalGraphInfo * from = queryExtra(fromExpr);
  190. LogicalGraphInfo * to = queryExtra(toExpr);
  191. if (kind == dependencyAtom)
  192. {
  193. LogicalGraphInfo * temp = from;
  194. from = to;
  195. to = temp;
  196. }
  197. if (from->subGraphId == to->subGraphId)
  198. addSimpleGraphEdge(curSubGraph(), from->id, to->id, from->outputCount++, 0, kind, label, nWay);
  199. else if (false)
  200. addSimpleGraphEdge(curSubGraph(), from->id, to->subGraphId, from->outputCount++, 0, kind, label, nWay);
  201. else
  202. addComplexGraphEdge(graph, from->subGraphId, to->subGraphId, from->id, to->id, from->outputCount++, kind, label);
  203. }
  204. void LogicalGraphCreator::createLogicalGraph(HqlExprArray & exprs)
  205. {
  206. graph.setown(createPTree("graph"));
  207. // beginSubGraph(NULL, false);
  208. ForEachItemIn(i, exprs)
  209. createRootGraphActivity(&exprs.item(i));
  210. // endSubGraph();
  211. Owned<IWUGraph> wug = wu->updateGraph("Logical");
  212. wug->setXGMMLTree(graph.getClear());
  213. wug->setType(GraphTypeEcl);
  214. }
  215. void LogicalGraphCreator::createRootGraphActivity(IHqlExpression * expr)
  216. {
  217. switch (expr->getOperator())
  218. {
  219. case no_comma:
  220. case no_compound:
  221. case no_sortlist:
  222. {
  223. ForEachChild(i, expr)
  224. createRootGraphActivity(expr->queryChild(i));
  225. return;
  226. }
  227. default:
  228. beginSubGraph(NULL, false);
  229. createGraphActivity(expr);
  230. endSubGraph(false);
  231. }
  232. }
  233. static void expandUnnamedFunnel(HqlExprArray & inputs, IHqlExpression * expr)
  234. {
  235. while ((expr->getOperator() == no_addfiles) && (expr->queryBody() == expr))
  236. {
  237. expandUnnamedFunnel(inputs, expr->queryChild(0));
  238. expr = expr->queryChild(1);
  239. }
  240. inputs.append(*LINK(expr));
  241. }
  242. void LogicalGraphCreator::createGraphActivity(IHqlExpression * expr)
  243. {
  244. LogicalGraphInfo * extra = queryExtra(expr);
  245. if (extra->globalId && !inSubQuery())
  246. {
  247. extra->id = extra->globalId;
  248. return;
  249. }
  250. //First generate children...
  251. //MORE: may want to do inputs first and dependents afterwards.
  252. _ATOM dependencyKind = dependencyAtom;
  253. unsigned first = getFirstActivityArgument(expr);
  254. unsigned last = first + getNumActivityArguments(expr);
  255. node_operator op = expr->getOperator();
  256. HqlExprArray inputs, dependents;
  257. bool defaultInputs = true;
  258. switch (op)
  259. {
  260. case no_setresult:
  261. case no_map:
  262. last = first;
  263. dependencyKind = NULL;
  264. break;
  265. case no_select:
  266. if (!isNewSelector(expr))
  267. {
  268. last = first;
  269. }
  270. break;
  271. case no_addfiles:
  272. expandUnnamedFunnel(inputs, expr->queryBody());
  273. defaultInputs = false;
  274. break;
  275. case no_colon:
  276. {
  277. if (!isWorkflowExpanded(expr))
  278. defaultInputs = false;
  279. gatherWorkflowActivities(expr, dependents);
  280. inputs.append(*LINK(expr->queryChild(0)));
  281. defaultInputs = false;
  282. break;
  283. }
  284. case no_forcelocal:
  285. case no_forcenolocal:
  286. case no_allnodes:
  287. case no_thisnode:
  288. {
  289. IHqlExpression * child = expr->queryChild(0);
  290. createSubGraphActivity(child);
  291. addDependent(dependents, child);
  292. defaultInputs = false;
  293. break;
  294. }
  295. }
  296. if (defaultInputs)
  297. {
  298. ForEachChild(i, expr)
  299. {
  300. IHqlExpression * cur = expr->queryChild(i);
  301. if ((i >= first && i < last) && !cur->isAttribute())
  302. inputs.append(*LINK(cur));
  303. else if (includeChildInDependents(expr, i))
  304. gatherGraphActivities(cur, dependents);
  305. }
  306. }
  307. ForEachItemIn(i0, inputs)
  308. createGraphActivity(&inputs.item(i0));
  309. //Generate the node for this activity
  310. unique_id_t id = ++seq;
  311. bool isGrouped = isGroupedActivity(expr);
  312. bool isLocal = !isGrouped && isLocalActivity(expr) && localChangesActivity(expr);
  313. StringBuffer tempText;
  314. beginActivity(getActivityText(expr, tempText), id);
  315. StringBuffer eclText;
  316. toECL(expr->queryBody(), eclText, false, true);
  317. addAttribute("ecl", eclText.str());
  318. addAttributeBool("grouped", isGrouped);
  319. addAttributeBool("local", isLocal);
  320. IHqlExpression * symbol = queryNamedSymbol(expr);
  321. if (symbol)
  322. {
  323. addAttribute("name", symbol->queryName());
  324. addAttribute("module", symbol->queryFullModuleName());
  325. addAttributeInt("line", symbol->getStartLine());
  326. addAttributeInt("column", symbol->getStartColumn());
  327. }
  328. endActivity();
  329. if (!inSubQuery())
  330. extra->globalId = id;
  331. extra->id = id;
  332. extra->subGraphId = subGraphId;
  333. ForEachItemIn(i1, inputs)
  334. {
  335. IHqlExpression * cur = &inputs.item(i1);
  336. if (!cur->isAttribute())
  337. {
  338. const char * label = NULL;
  339. switch (expr->getOperator())
  340. {
  341. case no_if:
  342. label = (i1 == 0) ? "True" : "False";
  343. break;
  344. case no_fetch:
  345. break;
  346. default:
  347. switch (getChildDatasetType(expr))
  348. {
  349. case childdataset_leftright:
  350. case childdataset_top_left_right:
  351. if (!isKeyedJoin(expr))
  352. {
  353. label = (i1 == 0) ? "LEFT" : "RIGHT";
  354. }
  355. break;
  356. }
  357. }
  358. connectActivities(cur, expr, NULL, label);
  359. }
  360. }
  361. ForEachItemIn(j, dependents)
  362. connectActivities(&dependents.item(j), expr, dependencyKind);
  363. }
  364. void LogicalGraphCreator::createSubGraphActivity(IHqlExpression * expr)
  365. {
  366. beginSubGraph(NULL, true);
  367. createGraphActivity(expr);
  368. endSubGraph(true);
  369. }
  370. IPropertyTree * LogicalGraphCreator::curSubGraph()
  371. {
  372. if (subGraphs.ordinality())
  373. return &subGraphs.tos();
  374. return graph;
  375. }
  376. void LogicalGraphCreator::endActivity()
  377. {
  378. activityNode.clear();
  379. }
  380. void LogicalGraphCreator::endSubGraph(bool nested)
  381. {
  382. subGraphs.pop();
  383. subGraphId = savedGraphId.pop();
  384. if (!nested)
  385. restoreSubGraphs();
  386. }
  387. static bool exprIsGlobal(IHqlExpression * expr)
  388. {
  389. HqlExprCopyArray inScope;
  390. expr->gatherTablesUsed(NULL, &inScope);
  391. return inScope.ordinality() == 0;
  392. }
  393. void LogicalGraphCreator::gatherWorkflowActivities(IHqlExpression * expr, HqlExprArray & dependents)
  394. {
  395. HqlExprArray actions;
  396. expr->queryChild(1)->unwindList(actions, no_comma);
  397. ForEachItemIn(i, actions)
  398. {
  399. IHqlExpression & cur = actions.item(i);
  400. switch (cur.getOperator())
  401. {
  402. case no_success:
  403. case no_failure:
  404. case no_recovery:
  405. {
  406. IHqlExpression * action = cur.queryChild(0);
  407. createRootGraphActivity(action);
  408. OwnedHqlExpr text = createConstant(getOpString(cur.getOperator()));
  409. OwnedHqlExpr labeled = createComma(LINK(action), LINK(text));
  410. addDependent(dependents, labeled);
  411. break;
  412. }
  413. }
  414. }
  415. }
  416. bool LogicalGraphCreator::gatherGraphActivities(IHqlExpression * expr, HqlExprArray & dependents)
  417. {
  418. LogicalGraphInfo * extra = queryExtra(expr);
  419. if (extra->noDependents)
  420. return false;
  421. //if no_select with new then create a child graph
  422. node_operator op = expr->getOperator();
  423. switch (op)
  424. {
  425. case no_select:
  426. {
  427. if (isNewSelector(expr))
  428. {
  429. if (exprIsGlobal(expr))
  430. createRootGraphActivity(expr);
  431. else
  432. createSubGraphActivity(expr);
  433. addDependent(dependents, expr);
  434. return true;
  435. }
  436. else
  437. return false;
  438. }
  439. case NO_AGGREGATE:
  440. {
  441. if (exprIsGlobal(expr))
  442. createRootGraphActivity(expr);
  443. else
  444. createSubGraphActivity(expr);
  445. addDependent(dependents, expr);
  446. return true;
  447. }
  448. case no_colon:
  449. {
  450. if (!isWorkflowExpanded(expr))
  451. return false;
  452. gatherWorkflowActivities(expr, dependents);
  453. }
  454. break;
  455. case no_attr:
  456. case no_attr_link:
  457. case no_attr_expr:
  458. case no_setmeta:
  459. return false;
  460. }
  461. if (extra->globalId && !inSubQuery())
  462. {
  463. extra->id = extra->globalId;
  464. addDependent(dependents, expr);
  465. return true;
  466. }
  467. switch (op)
  468. {
  469. case no_newkeyindex:
  470. case no_table:
  471. return false;
  472. }
  473. bool hasDependents = false;
  474. ForEachChild(i, expr)
  475. {
  476. if (gatherGraphActivities(expr->queryChild(i), dependents))
  477. hasDependents = true;
  478. }
  479. extra->noDependents = !hasDependents;
  480. return hasDependents;
  481. }
  482. static void capitaliseOpText(StringBuffer & out, IHqlExpression * expr)
  483. {
  484. const char * opText = getOpString(expr->getOperator());
  485. //Capitalise the keywords
  486. if (opText && *opText)
  487. {
  488. out.append(*opText);
  489. while (*++opText)
  490. out.append((char)tolower(*opText));
  491. }
  492. }
  493. const char * LogicalGraphCreator::getActivityText(IHqlExpression * expr, StringBuffer & temp)
  494. {
  495. if (expr->queryBody() != expr)
  496. {
  497. _ATOM module = includeModuleInText ? expr->queryFullModuleName() : NULL;
  498. _ATOM name = includeNameInText ? expr->queryName() : NULL;
  499. StringBuffer header;
  500. if (module)
  501. {
  502. if (name)
  503. {
  504. //module and name supplied. module may be the form <module>.<attr>.
  505. //If so, display <module>.<attr> if the name matches the attr, else <module>.<attr>::<name>
  506. const char * dot = strrchr(module->str(), '.');
  507. if (dot)
  508. {
  509. if (stricmp(dot+1, name->str()) == 0)
  510. header.append(module);
  511. else
  512. header.append(module).append("::").append(name);
  513. }
  514. else
  515. header.append(module).append(".").append(name);
  516. }
  517. else
  518. header.append(module);
  519. }
  520. else if (name)
  521. header.append(name);
  522. if (header.length())
  523. temp.append(header).append("\n");
  524. }
  525. if (displayJavadoc)
  526. {
  527. Owned<IPropertyTree> doc = expr->getDocumentation();
  528. if (doc)
  529. {
  530. doc->getProp("", temp);
  531. if (displayJavadocParameters && doc->hasProp("param"))
  532. {
  533. temp.append("\nParameters:");
  534. Owned<IPropertyTreeIterator> iter = doc->getElements("param");
  535. ForEach(*iter)
  536. {
  537. Owned<IPropertyTree> cur = &iter->get();
  538. temp.append("\n");
  539. cur->getProp("", temp);
  540. }
  541. }
  542. return temp.str();
  543. }
  544. }
  545. switch (expr->getOperator())
  546. {
  547. case no_table:
  548. {
  549. IHqlExpression * mode = expr->queryChild(2);
  550. switch (mode->getOperator())
  551. {
  552. case no_csv:
  553. case no_xml:
  554. temp.append(getOpString(expr->getOperator())).append(" ");
  555. break;
  556. }
  557. temp.append("Dataset");
  558. queryExpandFilename(temp, expr->queryChild(0));
  559. break;
  560. }
  561. break;
  562. case no_newkeyindex:
  563. {
  564. temp.append(getOpString(expr->getOperator()));
  565. queryExpandFilename(temp, expr->queryChild(3));
  566. break;
  567. }
  568. case no_newusertable:
  569. {
  570. temp.append("Table");
  571. break;
  572. }
  573. case no_output:
  574. {
  575. IHqlExpression * filename = queryRealChild(expr, 1);
  576. if (filename)
  577. {
  578. temp.append("Output");
  579. if (expr->hasProperty(xmlAtom))
  580. temp.append(" XML");
  581. else if (expr->hasProperty(csvAtom))
  582. temp.append(" CSV");
  583. queryExpandFilename(temp, filename);
  584. }
  585. else
  586. {
  587. IHqlExpression * seq = querySequence(expr);
  588. IHqlExpression * name = queryResultName(expr);
  589. temp.append(::getActivityText(TAKworkunitwrite)).append("\n");
  590. getStoredDescription(temp, seq, name, true);
  591. }
  592. break;
  593. }
  594. case no_temptable:
  595. case no_inlinetable:
  596. temp.append("Inline Dataset");
  597. break;
  598. case no_addfiles:
  599. temp.append(::getActivityText(TAKfunnel));
  600. break;
  601. case no_colon:
  602. {
  603. temp.append("Workflow:");
  604. HqlExprArray actions;
  605. expr->queryChild(1)->unwindList(actions, no_comma);
  606. ForEachItemIn(i, actions)
  607. {
  608. IHqlExpression * cur = &actions.item(i);
  609. if (!cur->isAttribute())
  610. {
  611. temp.append(' ');
  612. toECL(cur, temp, false, false);
  613. }
  614. }
  615. break;
  616. }
  617. case no_extractresult:
  618. case no_setresult:
  619. {
  620. IHqlExpression * sequence = queryPropertyChild(expr, sequenceAtom, 0);
  621. IHqlExpression * name = queryPropertyChild(expr, namedAtom, 0);
  622. temp.append("Store\n");
  623. getStoredDescription(temp, sequence, name, true);
  624. break;
  625. }
  626. case no_join:
  627. if (isKeyedJoin(expr))
  628. {
  629. temp.append("Keyed Join");
  630. IHqlExpression * index = expr->queryChild(1)->queryNormalizedSelector();
  631. if (index->getOperator() == no_newkeyindex)
  632. queryExpandFilename(temp, index->queryChild(3));
  633. }
  634. else
  635. temp.append("Join");
  636. break;
  637. case no_selfjoin:
  638. temp.append("Self Join");
  639. break;
  640. case no_select:
  641. temp.append("Select ");
  642. if (expr->isDataset())
  643. temp.append("Dataset");
  644. else if (expr->isDatarow())
  645. temp.append("Row");
  646. else
  647. temp.append("Field");
  648. temp.append("\n");
  649. temp.append(expr->queryChild(1)->queryName());
  650. break;
  651. case no_group:
  652. {
  653. IHqlExpression * sortlist = queryRealChild(expr, 1);
  654. if (sortlist && sortlist->numChildren() != 0)
  655. capitaliseOpText(temp, expr);
  656. else
  657. temp.append("Degroup");
  658. break;
  659. }
  660. default:
  661. if (expr->isAction() || expr->isDataset() || expr->isAggregate())
  662. capitaliseOpText(temp, expr);
  663. else
  664. temp.append("Result");
  665. break;
  666. }
  667. return temp.str();
  668. }
  669. bool LogicalGraphCreator::inSubQuery() const
  670. {
  671. return subGraphs.ordinality() > 1;
  672. }
  673. bool LogicalGraphCreator::isWorkflowExpanded(IHqlExpression * expr) const
  674. {
  675. IHqlExpression * actions = expr->queryChild(1);
  676. ForEachChild(i, actions)
  677. {
  678. IHqlExpression * cur = actions->queryChild(i);
  679. switch (cur->getOperator())
  680. {
  681. case no_persist:
  682. if (!expandPersist)
  683. return false;
  684. break;
  685. case no_stored:
  686. if (!expandStored)
  687. return false;
  688. break;
  689. default:
  690. return true;
  691. }
  692. }
  693. return true;
  694. }
  695. LogicalGraphInfo * LogicalGraphCreator::queryExtra(IHqlExpression * expr)
  696. {
  697. LogicalGraphInfo * extra = (LogicalGraphInfo *)expr->queryTransformExtra();
  698. if (!extra)
  699. {
  700. extra = new LogicalGraphInfo(expr);
  701. expr->setTransformExtraOwned(extra);
  702. }
  703. return extra;
  704. }
  705. void LogicalGraphCreator::restoreSubGraphs()
  706. {
  707. subGraphs.kill();
  708. unsigned level = savedLevels.pop();
  709. while (saved.ordinality() != level)
  710. subGraphs.append(saved.popGet());
  711. }
  712. void LogicalGraphCreator::saveSubGraphs()
  713. {
  714. savedLevels.append(saved.ordinality());
  715. ForEachItemInRev(i, subGraphs)
  716. saved.append(subGraphs.item(i));
  717. subGraphs.kill(true);
  718. }