hqlgraph.cpp 24 KB

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