hqlinline.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989
  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 "hqlcpp.ipp"
  23. #include "hqlhtcpp.ipp"
  24. #include "hqlutil.hpp"
  25. #include "hqlcpputil.hpp"
  26. #include "hqltcppc.ipp"
  27. #include "hqlwcpp.hpp"
  28. #include "hqlcatom.hpp"
  29. #include "hqlccommon.hpp"
  30. #include "hqlcerrors.hpp"
  31. #include "hqlpmap.hpp"
  32. #include "hqlinline.hpp"
  33. //I don't think the following is needed yet, but when it is, just enable following...
  34. //#define ONSTART_IN_NESTED_TOPLEVEL
  35. /*
  36. Allow the following operations to be evaluated in line:
  37. a) project of an dataset that can be iterated
  38. */
  39. enum
  40. {
  41. HEFprocessinline = 0x0001,
  42. HEFassigninline = 0x0002,
  43. HEFiterateinline = 0x0004,
  44. HEFevaluateinline = 0x0008, // can evaluate without any temporary dataset being created (temporary row is ok)
  45. HEFspillinline = 0x0010, // I'm not sure I can do this - because whether it spills depends on how it is being used.
  46. RETassign = HEFassigninline|HEFprocessinline,
  47. RETiterate = HEFiterateinline|HEFassigninline|HEFprocessinline,
  48. RETevaluate = HEFevaluateinline|HEFiterateinline|HEFassigninline|HEFprocessinline,
  49. };
  50. #define canAssignNoSpill(childFlags) ((childFlags & (HEFspillinline|HEFassigninline)) == HEFassigninline)
  51. #define canIterateNoSpill(childFlags) ((childFlags & (HEFspillinline|HEFiterateinline)) == HEFiterateinline)
  52. #define canEvaluateNoSpill(childFlags) ((childFlags & (HEFspillinline|HEFevaluateinline)) == HEFevaluateinline)
  53. // assign is superset of iterate, iterate is a superset of evaluate
  54. static unsigned getInlineFlags(BuildCtx * ctx, IHqlExpression * expr);
  55. static unsigned calcInlineFlags(BuildCtx * ctx, IHqlExpression * expr)
  56. {
  57. //The following improves a few graphs, but sometimes significantly (e.g., bc10.xhql, seep11.xhql)
  58. //But it would be really good if the code could be made context independent - then it could go in hqlattr and be cached.
  59. if (ctx)
  60. {
  61. if (expr->isDataset())
  62. {
  63. if (ctx->queryMatchExpr(expr))
  64. return RETevaluate;
  65. }
  66. else
  67. {
  68. if (ctx->queryAssociation(expr, AssocRow, NULL))
  69. return RETevaluate;
  70. }
  71. }
  72. node_operator op = expr->getOperator();
  73. switch (op)
  74. {
  75. case no_workunit_dataset:
  76. return RETassign;
  77. case no_alias:
  78. {
  79. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  80. if (childFlags == 0)
  81. return 0;
  82. if (isGrouped(expr))
  83. return RETevaluate;
  84. return RETevaluate|RETiterate;
  85. }
  86. case no_dataset_alias:
  87. return getInlineFlags(ctx, expr->queryChild(0));
  88. }
  89. if (isGrouped(expr))
  90. return 0;
  91. switch (op)
  92. {
  93. case no_select:
  94. //MORE: What about child datasets in nested records?
  95. if (isNewSelector(expr))
  96. {
  97. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  98. if ((childFlags & HEFevaluateinline) && isMultiLevelDatasetSelector(expr, false))
  99. childFlags &= ~HEFevaluateinline;
  100. return childFlags;
  101. }
  102. return RETevaluate;
  103. case no_newaggregate:
  104. {
  105. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  106. if ((childFlags == 0) || queryRealChild(expr, 3))
  107. return 0;
  108. if (canIterateNoSpill(childFlags))
  109. return RETevaluate;
  110. return RETevaluate|HEFspillinline;
  111. }
  112. case no_hqlproject:
  113. //can't do a skip inside an inline project - since the generated code doesn't allow "continue" to be used.
  114. if (transformContainsSkip(expr->queryChild(1)))
  115. return 0;
  116. case no_newusertable:
  117. {
  118. if (expr->hasProperty(prefetchAtom))
  119. return 0;
  120. IHqlExpression * ds = expr->queryChild(0);
  121. unsigned childFlags = getInlineFlags(ctx, ds);
  122. if (childFlags == 0)
  123. return 0;
  124. if (hasSingleRow(ds))
  125. {
  126. if (canEvaluateNoSpill(childFlags))
  127. return RETevaluate;
  128. return RETevaluate|HEFspillinline;
  129. }
  130. if (canIterateNoSpill(childFlags))
  131. return RETiterate;
  132. return RETiterate|HEFspillinline;
  133. }
  134. case no_selectmap:
  135. case no_selectnth:
  136. {
  137. IHqlExpression * ds = expr->queryChild(0);
  138. unsigned childFlags = getInlineFlags(ctx, ds);
  139. if (childFlags == 0)
  140. {
  141. if (isSelectSortedTop(expr))
  142. {
  143. childFlags = getInlineFlags(ctx, ds->queryChild(0));
  144. if (childFlags == 0)
  145. return 0;
  146. if (canIterateNoSpill(childFlags))
  147. return RETevaluate;
  148. return RETevaluate|HEFspillinline;
  149. }
  150. return 0;
  151. }
  152. if (isTrivialSelectN(expr) && canEvaluateNoSpill(childFlags))
  153. return RETevaluate;
  154. if (canIterateNoSpill(childFlags))
  155. return RETevaluate;
  156. return RETevaluate|HEFspillinline;
  157. }
  158. case no_filter:
  159. {
  160. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  161. if (childFlags == 0)
  162. return 0;
  163. if (canIterateNoSpill(childFlags))
  164. return RETiterate;
  165. if (filterIsTableInvariant(expr) && canAssignNoSpill(childFlags))
  166. return RETassign;
  167. return RETiterate|HEFspillinline;
  168. }
  169. case no_choosen:
  170. case no_index:
  171. {
  172. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  173. if (childFlags == 0)
  174. return 0;
  175. if (canIterateNoSpill(childFlags))
  176. return RETiterate;
  177. return RETiterate|HEFspillinline;
  178. }
  179. case no_limit:
  180. {
  181. if (expr->hasProperty(skipAtom) || expr->hasProperty(onFailAtom))
  182. return 0;
  183. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  184. if (childFlags == 0)
  185. return 0;
  186. unsigned flags = 0;
  187. if (canEvaluateNoSpill(childFlags))
  188. flags |= RETevaluate;
  189. if (canIterateNoSpill(childFlags))
  190. flags |= RETiterate;
  191. if (flags)
  192. return flags;
  193. return RETevaluate|HEFspillinline;
  194. }
  195. case no_catchds:
  196. return 0; // for the moment always do this out of line
  197. case no_table:
  198. return 0;
  199. case no_owned_ds:
  200. {
  201. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  202. if (childFlags == 0)
  203. return 0;
  204. return RETevaluate|HEFspillinline;
  205. }
  206. case no_addfiles:
  207. {
  208. unsigned ret = RETassign;
  209. for (unsigned i=0; i < 2; i++)
  210. {
  211. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(i));
  212. if (childFlags == 0)
  213. return 0;
  214. if (childFlags & HEFspillinline)
  215. ret |= HEFspillinline;
  216. }
  217. return ret;
  218. }
  219. case no_if:
  220. {
  221. unsigned ret = expr->isDatarow() ? RETevaluate : RETassign;
  222. for (unsigned i=1; i < 3; i++)
  223. {
  224. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(i));
  225. if (childFlags == 0)
  226. return 0;
  227. if (childFlags & HEFspillinline)
  228. ret |= HEFspillinline;
  229. }
  230. return ret;
  231. }
  232. case no_compound_childread:
  233. case no_compound_childnormalize:
  234. case no_compound_childaggregate:
  235. case no_compound_selectnew:
  236. case no_compound_inline:
  237. case no_datasetfromrow:
  238. case no_sorted:
  239. case no_distributed:
  240. case no_preservemeta:
  241. case no_nofold:
  242. case no_nohoist:
  243. case no_alias_scope:
  244. case no_serialize:
  245. case no_deserialize:
  246. case no_dataset_alias:
  247. return getInlineFlags(ctx, expr->queryChild(0));
  248. case no_forcegraph:
  249. return 0;
  250. case no_section:
  251. if (expr->hasProperty(graphAtom)) // force it to appear in the graph
  252. return 0;
  253. return getInlineFlags(ctx, expr->queryChild(0));
  254. case no_call:
  255. case no_externalcall: // no so sure about this - should possibly be assignable only. (also no_call above)
  256. case no_getresult:
  257. return expr->isDatarow() ? RETevaluate : RETassign;
  258. case no_getgraphresult:
  259. if (expr->hasProperty(_distributed_Atom))
  260. return 0;
  261. return expr->isDatarow() ? RETevaluate : RETassign;
  262. case no_temptable:
  263. return RETassign;
  264. case no_xmlproject:
  265. return RETiterate;
  266. case no_inlinetable:
  267. {
  268. if (transformListContainsSkip(expr->queryChild(0)))
  269. return 0;
  270. return RETassign;
  271. }
  272. case no_createrow:
  273. //MORE: We should probably be able to handle this...
  274. if (containsSkip(expr->queryChild(0)))
  275. return 0;
  276. return RETevaluate;
  277. case no_translated:
  278. return RETassign|RETiterate|RETevaluate;
  279. case no_null:
  280. case no_temprow:
  281. case no_projectrow:
  282. case no_left:
  283. case no_right:
  284. case no_top:
  285. case no_id2blob:
  286. case no_activerow:
  287. case no_typetransfer:
  288. case no_rows:
  289. case no_skip:
  290. case no_matchattr:
  291. case no_matchrow:
  292. case no_libraryinput:
  293. case no_fromxml:
  294. return RETevaluate;
  295. case no_apply:
  296. {
  297. unsigned childFlags = getInlineFlags(ctx, expr->queryChild(0));
  298. if (childFlags == 0)
  299. return 0;
  300. return RETevaluate|(childFlags & HEFspillinline);
  301. }
  302. case no_activetable:
  303. return RETassign;
  304. case no_join:
  305. {
  306. if (!expr->hasProperty(allAtom) || isKeyedJoin(expr))
  307. return 0;
  308. //conservatively check we support the attributes.
  309. unsigned max = expr->numChildren();
  310. for (unsigned i=4; i < max; i++)
  311. {
  312. IHqlExpression * cur = expr->queryChild(i);
  313. if (!cur->isAttribute())
  314. return 0;
  315. _ATOM name = cur->queryName();
  316. //possibly implement keep as well. (Local on a child join does nothing.)
  317. if ((name != leftouterAtom) && (name != leftonlyAtom) && (name != innerAtom) && (name != allAtom) && (name != localAtom) && !isInternalAttributeName(name))
  318. return 0;
  319. }
  320. unsigned childLFlags = getInlineFlags(ctx, expr->queryChild(0));
  321. unsigned childRFlags = getInlineFlags(ctx, expr->queryChild(1));
  322. if ((childLFlags == 0) || (childRFlags == 0))
  323. return 0;
  324. return RETassign|((childLFlags|childRFlags) & HEFspillinline);
  325. }
  326. case no_compound:
  327. return getInlineFlags(ctx, expr->queryChild(1));
  328. default:
  329. return 0;
  330. }
  331. }
  332. unsigned getInlineFlags(BuildCtx * ctx, IHqlExpression * expr)
  333. {
  334. //This could one day use flags stored in CHqlExpression if it was considered necessary.
  335. return calcInlineFlags(ctx, expr);
  336. }
  337. bool canProcessInline(BuildCtx * ctx, IHqlExpression * expr)
  338. {
  339. return getInlineFlags(ctx, expr) != 0;
  340. }
  341. bool canIterateInline(BuildCtx * ctx, IHqlExpression * expr)
  342. {
  343. return canIterateNoSpill(getInlineFlags(ctx, expr));
  344. }
  345. bool canEvaluateInline(BuildCtx * ctx, IHqlExpression * expr)
  346. {
  347. return canEvaluateNoSpill(getInlineFlags(ctx, expr));
  348. }
  349. bool canAssignInline(BuildCtx * ctx, IHqlExpression * expr)
  350. {
  351. return canAssignNoSpill(getInlineFlags(ctx, expr));
  352. }
  353. bool canAssignNotEvaluateInline(BuildCtx * ctx, IHqlExpression * expr)
  354. {
  355. unsigned flags = getInlineFlags(ctx, expr);
  356. return canAssignNoSpill(flags) && !canEvaluateNoSpill(flags);
  357. }
  358. bool alwaysEvaluatesToBound(IHqlExpression * expr)
  359. {
  360. switch (expr->getOperator())
  361. {
  362. case no_select:
  363. return !isMultiLevelDatasetSelector(expr, false);
  364. case no_owned_ds:
  365. case no_translated:
  366. case no_alias:
  367. case no_call:
  368. case no_externalcall: // no so sure about this - should possibly be assignable only. (also no_call above)
  369. case no_getresult:
  370. case no_getgraphresult:
  371. case no_workunit_dataset:
  372. case no_activetable:
  373. return !hasStreamedModifier(expr->queryType());
  374. case no_temptable:
  375. //MORE! when we have constant datasets
  376. default:
  377. return canEvaluateInline(NULL, expr);
  378. }
  379. }
  380. //============================================================================
  381. //============================================================================
  382. /*
  383. Notes on Graph distribution/localisation etc.
  384. There are several different things to take into account when noting the localisation of an activity, including the problem
  385. that meaning of "local" is overloaded. Currently we have something like the following, for each logical instance of an activity:
  386. Roxie
  387. SingleNode - only evaluated on a single node
  388. [Split, filter, project, rollup, sort, simpleresult]
  389. SingleNodeLocal - evaluated on a single node, and only access local files.
  390. [local keyed join, local index read]
  391. PrimarySlave - Evaluated on many nodes, only using local file parts [if any], interaction between nodes may occur on the primary
  392. [keyed join, index read, remote]
  393. Thor
  394. Master - only evalauted on the master
  395. [simpleresult]
  396. Distributed - Evaluated on many nodes
  397. [sort, distribute, group]
  398. DistributedIndependent - Evaluated on many nodes, no interaction between nodes
  399. [local sort, local group]
  400. DistributedLocal- Evaluated on many nodes using local file parts
  401. [local index read, local keyed join]
  402. HThor only has singlenode as an option
  403. Child Queries can be essentially be any of the roxie options. In addition there is the question of where the child will be
  404. evaluated in relation to its parent. The options are
  405. NoAccess - no context dependent information in the helper
  406. CoLocal - Will be evaluated on the same slave node as the parent
  407. NonLocal - May be evaluated on a different slave node from the parent
  408. We'll use the following logical flags to keep track of the different options:
  409. _singlenode_|_independentnodes_|_
  410. independent - no interaction between records on the different nodes.
  411. correlated - interaction between records on the different nodes.
  412. _localparts_|_allparts_
  413. - access local file parts or all file parts.
  414. allfile - access all file parts.
  415. local - either access local file parts, or no interaction between nodes.
  416. Ideally we want the expression tree to be independent of the current engine type, and so that derived attributes and optimizations
  417. can work independently of the engine if possible.
  418. => spill needs to indicate whether it is a purely memory spill
  419. => sort order and local interactions need resolving.
  420. */
  421. inline GraphLocalisation mergeLocalisation(GraphLocalisation l, GraphLocalisation r)
  422. {
  423. //options are GraphCoLocal, GraphNonLocal, GraphCoNonLocal, GraphNoAccess
  424. if (l == GraphNoAccess)
  425. return r;
  426. if (r == GraphNoAccess)
  427. return l;
  428. if ((l == GraphCoNonLocal) || (r == GraphCoNonLocal))
  429. return GraphCoNonLocal;
  430. if (l != r)
  431. return GraphCoNonLocal;
  432. return l;
  433. }
  434. // A minimal function to catch the obviously context invarient items.
  435. static bool accessesData(IHqlExpression * expr)
  436. {
  437. switch (expr->getOperator())
  438. {
  439. case no_attr:
  440. case no_constant:
  441. case no_record:
  442. return false;
  443. case no_assign:
  444. return accessesData(expr->queryChild(1));
  445. case no_assignall:
  446. case no_transform:
  447. case no_newtransform:
  448. case no_transformlist:
  449. case no_attr_expr:
  450. case no_fail:
  451. {
  452. ForEachChild(i, expr)
  453. {
  454. if (accessesData(expr->queryChild(i)))
  455. return true;
  456. }
  457. return false;
  458. }
  459. default:
  460. return true;
  461. }
  462. }
  463. GraphLocalisation queryActivityLocalisation(IHqlExpression * expr)
  464. {
  465. switch (expr->getOperator())
  466. {
  467. case no_compound_diskread:
  468. {
  469. if (isLocalActivity(expr) || expr->hasProperty(_colocal_Atom))
  470. return GraphCoLocal;
  471. //If a compound operation has been added, but with no other effect then don't allow that to change the localisation
  472. IHqlExpression * ds = expr->queryChild(0);
  473. if (ds->getOperator() == no_table)
  474. return queryActivityLocalisation(ds);
  475. return GraphNonLocal;
  476. }
  477. case no_table:
  478. if (expr->hasProperty(_noAccess_Atom))
  479. return GraphNoAccess;
  480. //fallthrough
  481. case no_keyindex:
  482. case no_newkeyindex:
  483. case no_compound_disknormalize:
  484. case no_compound_diskaggregate:
  485. case no_compound_diskcount:
  486. case no_compound_diskgroupaggregate:
  487. case no_compound_indexread:
  488. case no_compound_indexnormalize:
  489. case no_compound_indexaggregate:
  490. case no_compound_indexcount:
  491. case no_compound_indexgroupaggregate:
  492. if (!isLocalActivity(expr) && !expr->hasProperty(_colocal_Atom))
  493. return GraphNonLocal;
  494. break;
  495. case no_compound_fetch:
  496. case no_fetch:
  497. //Maybe there should be a version that only fetches locally???
  498. return GraphNonLocal; // simplest if we do it this way
  499. case no_allnodes:
  500. return GraphNonLocal; // simplest if we do it this way
  501. case no_join:
  502. case no_denormalize:
  503. case no_denormalizegroup:
  504. if (isKeyedJoin(expr) && !expr->hasProperty(localAtom))
  505. return GraphNonLocal;
  506. break;
  507. case no_output:
  508. if (expr->hasProperty(_spill_Atom))
  509. return GraphNoAccess;
  510. break;
  511. case no_setgraphresult:
  512. case no_spillgraphresult:
  513. case no_setgraphloopresult:
  514. case no_null:
  515. case no_split:
  516. case no_spill:
  517. case no_readspill:
  518. case no_writespill:
  519. case no_commonspill:
  520. case no_addfiles:
  521. case no_subgraph:
  522. case no_nofold:
  523. case no_nohoist:
  524. case no_regroup:
  525. case no_sorted:
  526. case no_distributed:
  527. case no_preservemeta:
  528. case no_grouped:
  529. case no_alias_scope:
  530. case no_sequential:
  531. case no_parallel:
  532. case no_deserialize:
  533. case no_serialize:
  534. case no_actionlist:
  535. case no_definesideeffect:
  536. case no_dataset_alias:
  537. return GraphNoAccess; // Will never access any data values from anywhere
  538. case no_hqlproject:
  539. case no_newusertable:
  540. //Many more of these could return GraphNoAccess if I determined that only constants and the input
  541. //row were accessed. Examples are project, sort, group etc. etc.
  542. //if (isSimpleProject(expr))
  543. /// return GraphNoAccess;
  544. return GraphCoLocal;
  545. case no_datasetfromrow:
  546. {
  547. if (getNumActivityArguments(expr) != 0)
  548. return GraphNoAccess;
  549. IHqlExpression * row = expr->queryChild(0);
  550. switch (row->getOperator())
  551. {
  552. case no_createrow:
  553. case no_null:
  554. return queryActivityLocalisation(row);
  555. }
  556. break;
  557. }
  558. case no_createrow:
  559. case no_inlinetable:
  560. {
  561. unsigned max = expr->numChildren();
  562. for (unsigned i=0; i<max; i++)
  563. {
  564. if (accessesData(expr->queryChild(i)))
  565. return GraphCoLocal;
  566. }
  567. return GraphNoAccess;
  568. }
  569. case no_group:
  570. case no_choosen:
  571. case no_limit:
  572. case no_catchds:
  573. case no_selectnth:
  574. {
  575. unsigned max = expr->numChildren();
  576. for (unsigned i=1; i<max; i++)
  577. {
  578. if (accessesData(expr->queryChild(i)))
  579. return GraphCoLocal;
  580. }
  581. return GraphNoAccess;
  582. }
  583. case no_newaggregate:
  584. if (!queryRealChild(expr, 3))
  585. {
  586. node_operator op = querySimpleAggregate(expr, false, false);
  587. if (op == no_existsgroup || op == no_countgroup)
  588. return GraphNoAccess;
  589. //Need to check if it accesses anything in the context!
  590. }
  591. break;
  592. }
  593. return GraphCoLocal;
  594. }
  595. bool isNonLocal(IHqlExpression * expr)
  596. {
  597. return (queryActivityLocalisation(expr) == GraphNonLocal);
  598. }
  599. static GraphLocalisation doGetGraphLocalisation(IHqlExpression * expr);
  600. static GraphLocalisation queryGraphLocalisation(IHqlExpression * expr)
  601. {
  602. GraphLocalisation localisation = queryActivityLocalisation(expr);
  603. if (isSourceActivity(expr))
  604. return localisation;
  605. unsigned firstChild = 0;
  606. unsigned numChildren;
  607. switch (expr->getOperator())
  608. {
  609. case no_if:
  610. firstChild = 1;
  611. numChildren = expr->numChildren();
  612. break;
  613. case no_compound:
  614. case no_subgraph:
  615. numChildren = expr->numChildren();
  616. break;
  617. case no_attr:
  618. case no_attr_expr:
  619. return GraphNoAccess;
  620. default:
  621. numChildren = getNumActivityArguments(expr);
  622. break;
  623. }
  624. for (unsigned i = firstChild; i < numChildren; i++)
  625. {
  626. localisation = mergeLocalisation(localisation, doGetGraphLocalisation(expr->queryChild(i)));
  627. if (localisation == GraphCoNonLocal)
  628. return localisation;
  629. }
  630. return localisation;
  631. }
  632. static GraphLocalisation doGetGraphLocalisation(IHqlExpression * expr)
  633. {
  634. IHqlExpression * cached = (IHqlExpression *)expr->queryTransformExtra();
  635. if (cached)
  636. return (GraphLocalisation)cached->queryValue()->getIntValue();
  637. GraphLocalisation ret = queryGraphLocalisation(expr);
  638. expr->setTransformExtraOwned(getSizetConstant((unsigned)ret));
  639. return ret;
  640. }
  641. bool HqlCppTranslator::isAlwaysCoLocal()
  642. {
  643. return targetHThor();
  644. }
  645. GraphLocalisation HqlCppTranslator::getGraphLocalisation(IHqlExpression * expr, bool isInsideChildQuery)
  646. {
  647. if (isAlwaysCoLocal()) return GraphCoLocal;
  648. if (targetThor() && !isInsideChildQuery)
  649. return GraphNonLocal;
  650. TransformMutexBlock lock;
  651. return doGetGraphLocalisation(expr);
  652. }
  653. bool HqlCppTranslator::isNeverDistributed(IHqlExpression * expr)
  654. {
  655. if (targetHThor())
  656. return true;
  657. switch (expr->getOperator())
  658. {
  659. case no_if:
  660. return expr->isAction();
  661. case no_setresult:
  662. return true;
  663. }
  664. return false;
  665. }
  666. //============================================================================
  667. ParentExtract::ParentExtract(HqlCppTranslator & _translator, PEtype _type, IHqlExpression * _graphId, GraphLocalisation _localisation, EvalContext * _container)
  668. : HqlExprAssociation(parentExtractMarkerExpr), translator(_translator), type(_type), graphId(_graphId)
  669. {
  670. localisation = _localisation;
  671. container = _container;
  672. if (!container)
  673. throwError(HQLERR_ExpectedParentContext);
  674. Owned<ITypeInfo> nullRow = makeRowType(queryNullRecord()->getType());
  675. Owned<ITypeInfo> declType = makeModifier(makeWrapperModifier(LINK(nullRow)), typemod_builder);
  676. StringBuffer extractName;
  677. translator.getUniqueId(extractName.append("ex"));
  678. boundBuilder.expr.setown(createVariable(extractName.str(), LINK(declType)));
  679. boundExtract.expr.setown(createVariable(extractName.str(), makeReferenceModifier(LINK(nullRow))));
  680. serialization = NULL;
  681. childSerialization = NULL;
  682. canDestroyExtract = false;
  683. }
  684. ParentExtract::~ParentExtract()
  685. {
  686. ::Release(serialization);
  687. }
  688. void ParentExtract::associateCursors(BuildCtx & declarectx, BuildCtx & evalctx, GraphLocalisation childLocalisation)
  689. {
  690. const CursorArray * boundCursors;
  691. switch (childLocalisation)
  692. {
  693. case GraphCoLocal:
  694. if (localisation == GraphRemote)
  695. boundCursors = &nonlocalBoundCursors;
  696. else if ((localisation == GraphCoLocal) || (localisation == GraphCoNonLocal))
  697. boundCursors = &colocalBoundCursors;
  698. else
  699. throwError2(HQLERR_InconsisentLocalisation, (int)childLocalisation, (int)localisation);
  700. break;
  701. case GraphNonLocal:
  702. case GraphRemote:
  703. if ((localisation == GraphCoLocal) || (localisation == GraphNoAccess))
  704. throwError2(HQLERR_InconsisentLocalisation, (int)childLocalisation, (int)localisation);
  705. boundCursors = &nonlocalBoundCursors;
  706. break;
  707. case GraphCoNonLocal:
  708. throwUnexpected();
  709. case GraphNoAccess:
  710. if (localisation == GraphRemote)
  711. boundCursors = &nonlocalBoundCursors;
  712. else
  713. {
  714. //Make sure we get an error if we do try and access something from the parent.
  715. return;
  716. }
  717. break;
  718. default:
  719. throwUnexpected();
  720. }
  721. ForEachItemIn(i, *boundCursors)
  722. {
  723. BoundRow & cur = boundCursors->item(i);
  724. IHqlExpression * aliasExpansion = cur.queryAliasExpansion();
  725. if (aliasExpansion)
  726. {
  727. //NB: If this ever generates any code then we will need to process it later...
  728. CHqlBoundExpr bound;
  729. translator.buildExpr(evalctx, aliasExpansion, bound);
  730. declarectx.associateOwn(*cur.clone(bound.expr));
  731. }
  732. else
  733. declarectx.associateOwn(OLINK(cur));
  734. }
  735. }
  736. void ParentExtract::beginCreateExtract(BuildCtx & ctx, bool doDeclare)
  737. {
  738. buildctx.setown(new BuildCtx(ctx));
  739. // Don't leak the serialization row into other sub calls - may want to do this a different way so
  740. // cses get commoned up by tagging the serialization somehow.
  741. //Probably do this later and allow it to be null. Will need a mechanism for calling some finalisation code
  742. //after all code is generated in order to do it.
  743. if (doDeclare)
  744. {
  745. BuildCtx * declarectx = buildctx;
  746. translator.getInvariantMemberContext(ctx, &declarectx, NULL, false, false);
  747. declarectx->addDeclare(boundBuilder.expr);
  748. }
  749. serialization = SerializationRow::create(translator, boundBuilder.expr, container ? container->queryActivity() : NULL);
  750. buildctx->associateOwn(*LINK(serialization));
  751. //Ensure the row is large enough to cope with any fixed fields - will only get relocated if variable fields are serialised
  752. HqlExprArray args;
  753. args.append(*LINK(serialization->queryBound()));
  754. args.append(*serialization->getFinalFixedSizeExpr());
  755. translator.callProcedure(*buildctx, ensureRowAvailableAtom, args);
  756. //Collect a list of cursors together... NB these are in reverse order..
  757. gatherActiveRows(*buildctx);
  758. childSerialization->setBuilder(this);
  759. }
  760. void ParentExtract::beginNestedExtract(BuildCtx & clonectx)
  761. {
  762. //Collect a list of cursors together... NB these are in reverse order..
  763. gatherActiveRows(clonectx);
  764. }
  765. void ParentExtract::beginReuseExtract()
  766. {
  767. //MORE: Should really check that the same rows are active...
  768. //Need to check if any additional rows, and if so bind them.
  769. childSerialization->setBuilder(this);
  770. }
  771. void ParentExtract::beginChildActivity(BuildCtx & declareCtx, BuildCtx & startCtx, GraphLocalisation childLocalisation, IHqlExpression * colocal, bool nested, bool ignoreSelf, ActivityInstance * activityRequiringCast)
  772. {
  773. //MORE: If we ever generate grand children - nested classes then the following isn't going to work
  774. //because accessing colocal->exNNN isn't going to get at the extract defined in the child class+passed to the grandchild.
  775. //Simplest would be to define the builders in the activity, and access them as activity->exXXX in the (grand)child.
  776. bool isColocal = (colocal != NULL);
  777. const CursorArray & boundCursors = isColocal ? colocalBoundCursors : nonlocalBoundCursors;
  778. ForEachItemIn(i, boundCursors)
  779. {
  780. BoundRow & cur = boundCursors.item(i);
  781. if (cur.isSerialization())
  782. {
  783. IHqlExpression * bound = cur.queryBound();
  784. if (!colocal && bound != boundExtract.expr)
  785. break;
  786. declareCtx.addDeclare(bound);
  787. OwnedHqlExpr src;
  788. if (bound == boundExtract.expr)
  789. {
  790. if (ignoreSelf)
  791. continue;
  792. //MORE: This cast is a hack. We should process const correctly in helper functions etc.
  793. if (!nested)
  794. src.setown(createVariable("(byte *)pe", bound->getType()));
  795. }
  796. if (!src)
  797. {
  798. src.setown(addMemberSelector(bound, colocal));
  799. //yuk yuk yuk.... A nasty solution to a nasty problem.
  800. //If the parent is a nested class with an extract (used by the compound group aggregate)
  801. //then any other extracts are going to be builders in the parent activity, but pointers in the nested
  802. //class. This means we need to add a .getBytes() call to extract the pointer
  803. //Also if we ever have grandchild nested classes they will need to change where the builder is defined.
  804. if (activityRequiringCast && (cur.queryActivity() == activityRequiringCast))
  805. {
  806. HqlExprArray args;
  807. args.append(*LINK(src));
  808. src.setown(translator.bindTranslatedFunctionCall(getBytesFromBuilderAtom, args));
  809. }
  810. }
  811. startCtx.addAssign(bound, src);
  812. }
  813. }
  814. associateCursors(declareCtx, startCtx, childLocalisation);
  815. }
  816. bool ParentExtract::canEvaluate(IHqlExpression * expr)
  817. {
  818. if (!buildctx)
  819. return false;
  820. return translator.canEvaluateInContext(*buildctx, expr);
  821. }
  822. void ParentExtract::endChildActivity()
  823. {
  824. }
  825. bool ParentExtract::requiresOnStart() const
  826. {
  827. switch (type)
  828. {
  829. case PETchild:
  830. case PETremote:
  831. case PETloop:
  832. case PETlibrary:
  833. return true;
  834. case PETnested:
  835. case PETcallback:
  836. return container->requiresOnStart();
  837. default:
  838. throwUnexpected();
  839. }
  840. }
  841. bool ParentExtract::insideChildQuery() const
  842. {
  843. switch (type)
  844. {
  845. case PETchild:
  846. return true;
  847. }
  848. return container->insideChildQuery();
  849. }
  850. bool ParentExtract::areGraphResultsAccessible(IHqlExpression * searchGraphId) const
  851. {
  852. if (graphId == searchGraphId)
  853. return true;
  854. switch (type)
  855. {
  856. case PETloop:
  857. return container->areGraphResultsAccessible(searchGraphId);
  858. }
  859. return false;
  860. }
  861. void ParentExtract::endCreateExtract(CHqlBoundExpr & boundExtract)
  862. {
  863. //NB: This can be called more than once - so need to be careful about any processing that
  864. //is done in here.
  865. childSerialization->setBuilder(NULL);
  866. CHqlBoundExpr boundSize;
  867. translator.getRecordSize(*buildctx, serialization->queryDataset(), boundSize);
  868. boundExtract.length.set(boundSize.expr);
  869. boundExtract.expr.set(boundBuilder.expr);
  870. }
  871. void ParentExtract::endUseExtract(BuildCtx & ctx)
  872. {
  873. childSerialization->finalize();
  874. //Not so sure about the lifetime of this. If the extract was saved for a later occasion (e.g., prefetch project) then may be destroyed too soon.
  875. if (canDestroyExtract)
  876. translator.doGenerateMetaDestruct(ctx, serialization->queryDataset(), childSerialization->queryRecord());
  877. }
  878. void ParentExtract::buildAssign(IHqlExpression * serializedTarget, IHqlExpression * originalValue)
  879. {
  880. translator.buildAssign(*buildctx, serializedTarget, originalValue);
  881. }
  882. //This function converts an expression evaluated in the parent to an expression that can be evaluated in the child.
  883. //Note, all extracts from all parent colocal activities are cloned into the child activity, so same expression is used to access them in the child
  884. void ParentExtract::ensureAccessible(BuildCtx & ctx, IHqlExpression * expr, const CHqlBoundExpr & bound, CHqlBoundExpr & tgt, IHqlExpression * colocal)
  885. {
  886. //MORE: Need to know whether it is
  887. //a) a member variable b) a serialization member or c) local and needs seerializing.
  888. //so when then do
  889. //a) add colcocal-> or create local references to the variables.
  890. //b) don't need to do anything
  891. //c) need to serialize and return value from that.
  892. //Probably need to tag global declares with an attribute - e.g., typemod_member
  893. //If activity is not colocal then always need to serialize
  894. if (colocal)
  895. {
  896. //I wish I didn't have to do this. wrapper classes have a cast added when they are converted to
  897. //expressions. I should probably look at removing it, but until that happens they need to be
  898. //stripped so the member variables get matched correctly.
  899. IHqlExpression * boundExpr = bound.expr;
  900. if (boundExpr->getOperator() == no_implicitcast)
  901. {
  902. IHqlExpression * uncast = boundExpr->queryChild(0);
  903. if (hasModifier(uncast->queryType(), typemod_wrapper) &&
  904. (queryUnqualifiedType(boundExpr->queryType()) == queryUnqualifiedType(uncast->queryType())))
  905. boundExpr = uncast;
  906. }
  907. //If already bound into a serialization then no need to do anything.
  908. ITypeInfo * serializedModifier = queryModifier(boundExpr->queryType(), typemod_serialized);
  909. if (serializedModifier)
  910. {
  911. //If serialized rebind the expression, rather than using the bound, otherwise temporary variables used for sizes
  912. //of fields can get lost (see extractbug.hql) for an example
  913. IHqlExpression * originalMapped = static_cast<IHqlExpression *>(serializedModifier->queryModifierExtra());
  914. translator.buildAnyExpr(ctx, originalMapped, tgt);
  915. tgt.expr.setown(addExpressionModifier(tgt.expr, typemod_serialized, originalMapped));
  916. return;
  917. }
  918. //Special case where this extract is used for member functions within the same class
  919. if (hasModifier(boundExpr->queryType(), typemod_member))
  920. {
  921. if (colocal == colocalSameClassPreserveExpr)
  922. {
  923. tgt.set(bound);
  924. return;
  925. }
  926. //Need to create new (reference) members in the new class, and code to assign them in
  927. //the setParent() call.
  928. tgt.isAll.setown(addMemberSelector(bound.isAll, colocal));
  929. tgt.count.setown(addMemberSelector(bound.count, colocal));
  930. tgt.length.setown(addMemberSelector(bound.length, colocal));
  931. tgt.expr.setown(addMemberSelector(boundExpr, colocal));
  932. return;
  933. }
  934. }
  935. //nonLocal child and local variables to a colocal child.
  936. assertex(childSerialization);
  937. OwnedHqlExpr value = bound.getTranslatedExpr();
  938. OwnedHqlExpr mapped = childSerialization->ensureSerialized(value, canDestroyExtract ? colocal : NULL, false);
  939. translator.buildAnyExpr(ctx, mapped, tgt);
  940. //add a serialized modifier to the type so we can track expressions already serialized, the extra saves the original mappiing
  941. tgt.expr.setown(addExpressionModifier(tgt.expr, typemod_serialized, mapped));
  942. ctx.associateExpr(expr, tgt);
  943. }
  944. void ParentExtract::addSerializedExpression(IHqlExpression * value, ITypeInfo * type)
  945. {
  946. OwnedHqlExpr mapped = childSerialization->addSerializedValue(value, type, NULL, false);
  947. }
  948. AliasKind ParentExtract::evaluateExpression(BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt, IHqlExpression * colocal, bool evaluateLocally)
  949. {
  950. CHqlBoundExpr bound;
  951. AliasKind kind;
  952. if (buildctx)
  953. kind = translator.doBuildAliasValue(*buildctx, value, bound);
  954. else
  955. kind = container->evaluateExpression(ctx, value, bound, evaluateLocally);
  956. if (kind != NotFoundAlias)
  957. ensureAccessible(ctx, value, bound, tgt, colocal);
  958. if (!colocal)
  959. return RuntimeAlias;
  960. return kind;
  961. }
  962. void ParentExtract::gatherActiveRows(BuildCtx & ctx)
  963. {
  964. //Collect a list of cursors together... NB these are in reverse order..
  965. CursorArray activeRows;
  966. RowAssociationIterator iter(ctx);
  967. ForEach(iter)
  968. {
  969. BoundRow & cur = iter.get();
  970. if ((cur.querySide() != no_self) && !cur.isBuilder())
  971. {
  972. bool ok = true;
  973. IHqlExpression * represents = cur.queryDataset();
  974. switch(represents->getOperator())
  975. {
  976. case no_null:
  977. ok = !represents->hasProperty(clearAtom); // Don't serialize rows used as default clear rows
  978. break;
  979. case no_anon:
  980. ok = !represents->hasProperty(selfAtom);
  981. break;
  982. default:
  983. if (cur.isResultAlias())
  984. ok = false;
  985. //MORE: This should only be done if the child query etc. actually references the datarow.
  986. //ideally from a colocal activity.
  987. #if 0
  988. //Theoretically the following is true. However it can mean that for the cost of serializing an extra 4 bytes here and
  989. //there you end up serializing several hundred in some other situations.
  990. //So on balance, worth including them even if strictly unnecessary.
  991. if (represents->isDatarow() && !isAlwaysActiveRow(represents))
  992. ok = false;
  993. #endif
  994. break;
  995. }
  996. if (ok)
  997. activeRows.append(OLINK(cur));
  998. }
  999. }
  1000. //NB: Serialization needs to be added processed first in the child scope
  1001. if (serialization)
  1002. {
  1003. childSerialization = (SerializationRow *)serialization->clone(boundExtract.expr);
  1004. colocalBoundCursors.append(*childSerialization);
  1005. nonlocalBoundCursors.append(*LINK(childSerialization));
  1006. }
  1007. //MORE: Should possibly create two sets of cursors one if children are colocal, other if children aren't
  1008. //so colocal cursors can be used whereever possible. Would change following to localisation != GraphNonLocal
  1009. //and remove else
  1010. if (localisation == GraphCoLocal || localisation == GraphCoNonLocal)
  1011. {
  1012. OwnedHqlExpr colocal = createQuoted("colocal", makeVoidType());
  1013. ForEachItemInRev(i, activeRows)
  1014. {
  1015. BoundRow & cur = activeRows.item(i);
  1016. IHqlExpression * bound = cur.queryBound();
  1017. OwnedHqlExpr colocalBound = addMemberSelector(bound, colocal);
  1018. BoundRow * newRow = NULL;
  1019. if (cur.isSerialization() || cur.queryDataset()->getOperator() == no_pseudods)
  1020. {
  1021. //an extract/serialization. Same cursor is added to all colocal children.
  1022. newRow = LINK(&cur);
  1023. }
  1024. else if (cur.queryAliasExpansion() || cur.isNonLocal())
  1025. {
  1026. //A cursor who's pointer has already been serialized into an extract
  1027. //NB: Alias expansions get rebound when they are bound into the context.
  1028. newRow = LINK(&cur);
  1029. }
  1030. else if (!cur.isBinary())
  1031. {
  1032. //CSV and xml datasets need their elements serialized into the parent extract
  1033. newRow = new NonLocalIndirectRow(cur, NULL, childSerialization);
  1034. }
  1035. else if (serialization)
  1036. {
  1037. //A cursor active in the current scope => add it to the extract, and create an alias in the
  1038. //child contexts.
  1039. //Need to add these fields to the extract record, and do the assignments at the point of call
  1040. Owned<ITypeInfo> fieldType = makeRowReferenceType(cur.queryDataset());
  1041. if (hasOutOfLineModifier(bound->queryType()))
  1042. fieldType.setown(makeAttributeModifier(LINK(fieldType), getLinkCountedAttr()));
  1043. OwnedHqlExpr expandedAlias = serialization->createField(NULL, fieldType);
  1044. OwnedHqlExpr castSource = createValue(no_implicitcast, LINK(fieldType), LINK(bound));
  1045. OwnedHqlExpr translated = createTranslated(castSource);
  1046. translator.buildAssign(ctx, expandedAlias, translated);
  1047. newRow = new BoundAliasRow(cur, NULL, expandedAlias);
  1048. newRow->setInherited(true);
  1049. }
  1050. else
  1051. {
  1052. //A row defined in a activity class instance, being used from a nested class.
  1053. //E.g., row used to clear a value. Should be possible to recreate in the nested class
  1054. if (cur.getKind() != AssocRow)
  1055. throwUnexpected();
  1056. }
  1057. if (newRow)
  1058. colocalBoundCursors.append(* newRow);
  1059. }
  1060. //May also need to associate any counters in scope. May be more than one!
  1061. //Possibly other things like filepositions, ..... How do I recognise them all?
  1062. //Use a dynamic offset map to represent whatever is serialized.
  1063. //MORE: This may actually mean we want to bind these non-row contexts on demand - but then it is harder to share.
  1064. }
  1065. if (localisation != GraphCoLocal)
  1066. {
  1067. ForEachItemInRev(i, activeRows)
  1068. {
  1069. BoundRow & cur = activeRows.item(i);
  1070. nonlocalBoundCursors.append(*new NonLocalIndirectRow(cur, NULL, childSerialization));
  1071. }
  1072. }
  1073. }
  1074. //----------------------------------------------------------------------------
  1075. ParentExtract * HqlCppTranslator::createExtractBuilder(BuildCtx & ctx, PEtype type, IHqlExpression * graphId, GraphLocalisation localisation, bool doDeclare)
  1076. {
  1077. ParentExtract * extractor = NULL;
  1078. // if (localisation == GraphCoLocal)
  1079. // extract = checkForPreexistingExtract - find a bound association before a row association is found;
  1080. if (!extractor)
  1081. {
  1082. extractor = new ParentExtract(*this, type, graphId, localisation, queryEvalContext(ctx));
  1083. extractor->beginCreateExtract(ctx, doDeclare);
  1084. }
  1085. else
  1086. extractor->beginReuseExtract();
  1087. return extractor;
  1088. }
  1089. ParentExtract * HqlCppTranslator::createExtractBuilder(BuildCtx & ctx, PEtype type, IHqlExpression * graphId, IHqlExpression * expr, bool doDeclare)
  1090. {
  1091. if (isAlwaysCoLocal())
  1092. return createExtractBuilder(ctx, type, graphId, GraphCoLocal, true);
  1093. bool isInsideChildQuery = (type == PETchild) || insideChildQuery(ctx);
  1094. return createExtractBuilder(ctx, type, graphId, getGraphLocalisation(expr, isInsideChildQuery), true);
  1095. }
  1096. //----------------------------------------------------------------------------
  1097. AliasKind HqlCppTranslator::buildExprInCorrectContext(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, bool evaluateLocally)
  1098. {
  1099. EvalContext * instance = queryEvalContext(ctx);
  1100. if (instance)
  1101. return instance->evaluateExpression(ctx, expr, tgt, evaluateLocally);
  1102. if (ctx.getMatchExpr(expr, tgt))
  1103. return RuntimeAlias;
  1104. return NotFoundAlias;
  1105. }
  1106. //---------------------------------------------------------------------------
  1107. void CtxCollection::createFunctionStructure(HqlCppTranslator & translator, BuildCtx & ctx, bool canEvaluate, const char * serializeFunc)
  1108. {
  1109. clonectx.set(ctx);
  1110. clonectx.addGroup();
  1111. if (serializeFunc)
  1112. {
  1113. BuildCtx condctx(ctx);
  1114. OwnedHqlExpr cond = createVariable("in", makeBoolType());
  1115. IHqlStmt * stmt = condctx.addFilter(cond);
  1116. deserializectx.setown(new BuildCtx(condctx));
  1117. condctx.selectElse(stmt);
  1118. evalctx.setown(new BuildCtx(condctx));
  1119. //virtual void serializeCreateContext(MemoryBuffer & out)
  1120. serializectx.setown(new BuildCtx(declarectx));
  1121. StringBuffer s;
  1122. s.append("virtual void ").append(serializeFunc).append("(MemoryBuffer & out)");
  1123. serializectx->addQuotedCompoundOpt(s.str());
  1124. } else if (canEvaluate)
  1125. {
  1126. evalctx.setown(new BuildCtx(ctx));
  1127. evalctx->addGroup();
  1128. }
  1129. childctx.set(ctx);
  1130. }
  1131. //---------------------------------------------------------------------------
  1132. EvalContext::EvalContext(HqlCppTranslator & _translator, ParentExtract * _parentExtract, EvalContext * _parent)
  1133. : HqlExprAssociation(classMarkerExpr), translator(_translator)
  1134. {
  1135. parent = _parent;
  1136. parentExtract.set(_parentExtract);
  1137. }
  1138. IHqlExpression * EvalContext::createGraphLookup(unique_id_t id, bool isChild)
  1139. {
  1140. assertex(parent);
  1141. return parent->createGraphLookup(id, isChild);
  1142. }
  1143. bool EvalContext::needToEvaluateLocally(BuildCtx & ctx, IHqlExpression * expr)
  1144. {
  1145. return mustEvaluateInContext(ctx, expr);
  1146. }
  1147. bool EvalContext::evaluateInParent(BuildCtx & ctx, IHqlExpression * expr, bool hasOnStart)
  1148. {
  1149. if (!parent)
  1150. return false;
  1151. if (parent->isLibraryContext())
  1152. return (expr->getOperator() == no_libraryinput);
  1153. switch (expr->getOperator())
  1154. {
  1155. case no_libraryinput:
  1156. case no_rows:
  1157. case no_filepos:
  1158. case no_file_logicalname:
  1159. case no_counter:
  1160. case no_variable: // this really should happen
  1161. return true; // would have been bound if found
  1162. case no_id2blob:
  1163. return !queryBlobHelper(ctx, expr->queryChild(0));
  1164. case no_loopcounter:
  1165. return !translator.isCurrentActiveGraph(ctx, expr->queryChild(0));
  1166. case no_getgraphresult:
  1167. return !translator.isCurrentActiveGraph(ctx, expr->queryChild(1));
  1168. case no_failcode:
  1169. case no_failmessage:
  1170. case no_fail:
  1171. return !ctx.queryMatchExpr(activeFailureMarkerExpr);
  1172. case no_xmltext:
  1173. case no_xmlunicode:
  1174. case no_xmlproject:
  1175. return !ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  1176. case no_matched:
  1177. case no_matchtext:
  1178. case no_matchunicode:
  1179. case no_matchlength:
  1180. case no_matchposition:
  1181. case no_matchrow:
  1182. case no_matchutf8:
  1183. return !ctx.queryMatchExpr(activeNlpMarkerExpr);
  1184. case no_matchattr:
  1185. return !ctx.queryMatchExpr(activeNlpMarkerExpr) && !ctx.queryMatchExpr(activeProductionMarkerExpr);
  1186. }
  1187. //Some function of the above => eveluate where we are...
  1188. if (isContextDependent(expr))
  1189. return false;
  1190. if (!containsActiveDataset(expr))
  1191. return true;//isColocal();
  1192. //If can evaluate in parent's start context then always worth doing there.
  1193. if (parent->isRowInvariant(expr))
  1194. return true;
  1195. if (parentExtract->canEvaluate(expr))
  1196. {
  1197. if (!isColocal() || !hasOnStart)
  1198. return true;
  1199. if (translator.queryEvaluateCoLocalRowInvariantInExtract())
  1200. return true;
  1201. return false;
  1202. }
  1203. return false;
  1204. }
  1205. bool EvalContext::insideChildQuery() const
  1206. {
  1207. if (parentExtract)
  1208. return parentExtract->insideChildQuery();
  1209. if (parent)
  1210. return parent->insideChildQuery();
  1211. return false;
  1212. }
  1213. bool EvalContext::requiresOnStart() const
  1214. {
  1215. if (parentExtract)
  1216. return parentExtract->requiresOnStart();
  1217. if (parent)
  1218. return parent->requiresOnStart();
  1219. return false;
  1220. }
  1221. ActivityInstance * EvalContext::queryActivity()
  1222. {
  1223. if (parent)
  1224. return parent->queryActivity();
  1225. return NULL;
  1226. }
  1227. bool EvalContext::areGraphResultsAccessible(IHqlExpression * searchGraphId) const
  1228. {
  1229. if (parentExtract)
  1230. return parentExtract->areGraphResultsAccessible(searchGraphId);
  1231. if (parent)
  1232. return parent->areGraphResultsAccessible(searchGraphId);
  1233. return false;
  1234. }
  1235. IHqlExpression * HqlCppTranslator::doCreateGraphLookup(BuildCtx & declarectx, BuildCtx & resolvectx, unique_id_t id, const char * activity, bool isChild)
  1236. {
  1237. StringBuffer s, var;
  1238. if (isChild)
  1239. {
  1240. appendUniqueId(var.append("child"), id);
  1241. s.clear().append("Owned<IThorChildGraph> ").append(var).append(";");
  1242. declarectx.addQuoted(s);
  1243. s.clear().append(var).append(".setown(ctx->resolveChildQuery(").append(id).append(",").append(activity).append("));");
  1244. resolvectx.addQuoted(s);
  1245. }
  1246. else
  1247. {
  1248. //NB: resolveLocalQuery (unlike children) can't link otherwise you get a cicular dependency.
  1249. appendUniqueId(var.append("graph"), id);
  1250. OwnedHqlExpr memberExpr = createQuoted(var, makeBoolType());
  1251. if (declarectx.queryMatchExpr(memberExpr))
  1252. return memberExpr.getClear();
  1253. s.clear().append("ILocalGraph * ").append(var).append(";");
  1254. declarectx.addQuoted(s);
  1255. declarectx.associateExpr(memberExpr, memberExpr);
  1256. s.clear().append(var).append(" = ctx->resolveLocalQuery(").append(id).append(");");
  1257. resolvectx.addQuoted(s);
  1258. }
  1259. return createQuoted(var, makeBoolType());
  1260. }
  1261. //---------------------------------------------------------------------------
  1262. ClassEvalContext::ClassEvalContext(HqlCppTranslator & _translator, ParentExtract * _parentExtract, EvalContext * _parent, BuildCtx & createctx, BuildCtx & startctx)
  1263. : EvalContext(_translator, _parentExtract, _parent), onCreate(createctx), onStart(startctx)
  1264. {
  1265. }
  1266. IHqlExpression * ClassEvalContext::cloneExprInClass(CtxCollection & ctxs, IHqlExpression * expr)
  1267. {
  1268. if (!expr)
  1269. return NULL;
  1270. if (expr->getOperator() != no_pselect)
  1271. return LINK(expr);
  1272. LinkedHqlExpr value = expr;
  1273. Linked<ITypeInfo> type = expr->queryType();
  1274. assertex(hasModifier(type, typemod_member));
  1275. if (isTypePassedByAddress(type))
  1276. {
  1277. value.setown(getPointer(value));
  1278. type.setown(value->getType());
  1279. }
  1280. else
  1281. {
  1282. if (hasModifier(type, typemod_wrapper))
  1283. {
  1284. type.setown(removeModifier(type, typemod_wrapper));
  1285. value.setown(createValue(no_implicitcast, LINK(type), LINK(value)));
  1286. }
  1287. }
  1288. if (!hasModifier(type, typemod_member))
  1289. type.setown(makeModifier(value->getType(), typemod_member));
  1290. OwnedHqlExpr decl = ctxs.declarectx.getTempDeclare(type, NULL);
  1291. ctxs.clonectx.addAssign(decl, value);
  1292. return LINK(decl);
  1293. }
  1294. void ClassEvalContext::cloneAliasInClass(CtxCollection & ctxs, const CHqlBoundExpr & bound, CHqlBoundExpr & tgt)
  1295. {
  1296. // assertex(!bound.count);
  1297. ensureHelpersExist();
  1298. tgt.isAll.setown(cloneExprInClass(ctxs, bound.isAll));
  1299. tgt.count.setown(cloneExprInClass(ctxs, bound.count));
  1300. tgt.length.setown(cloneExprInClass(ctxs, bound.length));
  1301. tgt.expr.setown(cloneExprInClass(ctxs, bound.expr));
  1302. }
  1303. void ClassEvalContext::createMemberAlias(CtxCollection & ctxs, BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt)
  1304. {
  1305. if (ctxs.declarectx.getMatchExpr(value, tgt))
  1306. return;
  1307. //Should never be called for a nested class - that should be done in the context.
  1308. assertex(ctxs.evalctx != NULL);
  1309. translator.expandAliases(*ctxs.evalctx, value);
  1310. CHqlBoundTarget tempTarget;
  1311. translator.buildTempExpr(*ctxs.evalctx, ctxs.declarectx, tempTarget, value, FormatNatural, false);
  1312. ensureSerialized(ctxs, tempTarget);
  1313. tgt.setFromTarget(tempTarget);
  1314. ctxs.declarectx.associateExpr(value, tgt);
  1315. }
  1316. void ClassEvalContext::doCallNestedHelpers(const char * member, const char * activity)
  1317. {
  1318. StringBuffer s;
  1319. onCreate.childctx.addQuoted(s.clear().append(member).append(".onCreate(ctx, ").append(activity).append(");"));
  1320. if (requiresOnStart())
  1321. onStart.childctx.addQuoted(s.clear().append(member).append(".onStart();"));
  1322. }
  1323. void ClassEvalContext::ensureSerialized(CtxCollection & ctxs, const CHqlBoundTarget & target)
  1324. {
  1325. if (ctxs.serializectx)
  1326. translator.ensureSerialized(target, *ctxs.serializectx, *ctxs.deserializectx, "*in", "out");
  1327. }
  1328. AliasKind ClassEvalContext::evaluateExpression(BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt, bool evaluateLocally)
  1329. {
  1330. if (onStart.declarectx.getMatchExpr(value, tgt))
  1331. {
  1332. if (onCreate.declarectx.queryMatchExpr(value))
  1333. return CreateTimeAlias;
  1334. return StartTimeAlias;
  1335. }
  1336. if (ctx.getMatchExpr(value, tgt))
  1337. return RuntimeAlias;
  1338. ///If contains a nasty like counter/matchtext then evaluate here for the moment...
  1339. if (!needToEvaluateLocally(ctx, value))
  1340. {
  1341. if (evaluateInParent(ctx, value, (onStart.evalctx != NULL)))
  1342. {
  1343. if (!parentExtract)
  1344. throwError(HQLERR_NoParentExtract);
  1345. CHqlBoundExpr bound;
  1346. AliasKind kind = parentExtract->evaluateExpression(ctx, value, bound, colocalMember, evaluateLocally);
  1347. switch (kind)
  1348. {
  1349. case RuntimeAlias:
  1350. tgt.set(bound);
  1351. break;
  1352. case CreateTimeAlias:
  1353. cloneAliasInClass(onCreate, bound, tgt);
  1354. onCreate.declarectx.associateExpr(value, tgt);
  1355. break;
  1356. case StartTimeAlias:
  1357. cloneAliasInClass(onStart, bound, tgt);
  1358. onStart.declarectx.associateExpr(value, tgt);
  1359. break;
  1360. }
  1361. return kind;
  1362. }
  1363. if (!evaluateLocally)
  1364. return NotFoundAlias;
  1365. if (!isContextDependentExceptGraph(value))
  1366. {
  1367. if (!isContextDependent(value) && !containsActiveDataset(value))
  1368. {
  1369. createMemberAlias(onCreate, ctx, value, tgt);
  1370. return CreateTimeAlias;
  1371. }
  1372. bool evaluateInOnStart = false;
  1373. if (isRowInvariant(value) && onStart.evalctx)
  1374. {
  1375. evaluateInOnStart = true;
  1376. if (isGraphDependent(value))
  1377. {
  1378. //Need to find out which graph it is dependent on, and check that isn't defined locally
  1379. HqlExprCopyArray graphs;
  1380. gatherGraphReferences(graphs, value, true);
  1381. if (graphs.ordinality() != 0)
  1382. evaluateInOnStart = false;
  1383. }
  1384. }
  1385. if (evaluateInOnStart)
  1386. {
  1387. translator.traceExpression("alias", value);
  1388. createMemberAlias(onStart, ctx, value, tgt);
  1389. return StartTimeAlias;
  1390. }
  1391. }
  1392. }
  1393. if (!evaluateLocally)
  1394. return NotFoundAlias;
  1395. translator.expandAliases(ctx, value);
  1396. translator.buildTempExpr(ctx, value, tgt);
  1397. return RuntimeAlias;
  1398. }
  1399. void ClassEvalContext::tempCompatiablityEnsureSerialized(const CHqlBoundTarget & tgt)
  1400. {
  1401. ensureSerialized(onCreate, tgt);
  1402. }
  1403. bool ClassEvalContext::isRowInvariant(IHqlExpression * expr)
  1404. {
  1405. return translator.canEvaluateInContext(onStart.declarectx, expr);
  1406. }
  1407. //If this is called on something that is shared, then need to ensure it will be valid for all subsequent calls
  1408. //therefore, we can't test whether it is inside an onCreate function since that may not be true the first time, but may be subsequent times.
  1409. //and we need to generate the code where we guarantee it will have been executed before (almost) everything else.
  1410. //if not independent, then it can't be shared - so generate it after the code to extract temporary values
  1411. bool ClassEvalContext::getInvariantMemberContext(BuildCtx * ctx, BuildCtx * * declarectx, BuildCtx * * initctx, bool isIndependentMaybeShared, bool invariantEachStart)
  1412. {
  1413. if (invariantEachStart)
  1414. {
  1415. if (declarectx)
  1416. *declarectx = &onStart.declarectx;
  1417. if (initctx && (!ctx || isIndependentMaybeShared || !ctx->queryMatchExpr(insideOnStartMarker)))
  1418. {
  1419. ensureHelpersExist();
  1420. if (isIndependentMaybeShared)
  1421. *initctx = &onStart.clonectx; // before anything else happens.
  1422. else
  1423. *initctx = &onStart.childctx; // after global variables have been read or de-serialized.
  1424. }
  1425. }
  1426. else
  1427. {
  1428. if (declarectx)
  1429. *declarectx = &onCreate.declarectx;
  1430. if (initctx && (!ctx || isIndependentMaybeShared || !ctx->queryMatchExpr(insideOnCreateMarker)))
  1431. {
  1432. ensureHelpersExist();
  1433. if (isIndependentMaybeShared)
  1434. *initctx = &onCreate.clonectx; // before anything else happens.
  1435. else
  1436. *initctx = &onCreate.childctx; // after global variables have been read or de-serialized.
  1437. }
  1438. }
  1439. return true;
  1440. }
  1441. //---------------------------------------------------------------------------
  1442. GlobalClassEvalContext::GlobalClassEvalContext(HqlCppTranslator & _translator, ParentExtract * _parentExtract, EvalContext * _parent, BuildCtx & createctx, BuildCtx & startctx)
  1443. : ClassEvalContext(_translator, _parentExtract, _parent, createctx, startctx)
  1444. {
  1445. }
  1446. void GlobalClassEvalContext::ensureHelpersExist()
  1447. {
  1448. }
  1449. void GlobalClassEvalContext::callNestedHelpers(const char * member)
  1450. {
  1451. doCallNestedHelpers(member, "this");
  1452. }
  1453. //---------------------------------------------------------------------------
  1454. ActivityEvalContext::ActivityEvalContext(HqlCppTranslator & _translator, ActivityInstance * _activity, ParentExtract * _parentExtract, EvalContext * _parent, IHqlExpression * _colocal, BuildCtx & createctx, BuildCtx & startctx)
  1455. : ClassEvalContext(_translator, _parentExtract, _parent, createctx, startctx)
  1456. {
  1457. activity = _activity;
  1458. colocalMember.set(_colocal);
  1459. }
  1460. IHqlExpression * ActivityEvalContext::createGraphLookup(unique_id_t id, bool isChild)
  1461. {
  1462. return translator.doCreateGraphLookup(onCreate.declarectx, onCreate.childctx, id, "this", isChild);
  1463. }
  1464. void ActivityEvalContext::ensureHelpersExist()
  1465. {
  1466. }
  1467. void ActivityEvalContext::callNestedHelpers(const char * member)
  1468. {
  1469. doCallNestedHelpers(member, "this");
  1470. }
  1471. ActivityInstance * ActivityEvalContext::queryActivity()
  1472. {
  1473. return activity;
  1474. }
  1475. //---------------------------------------------------------------------------
  1476. NestedEvalContext::NestedEvalContext(HqlCppTranslator & _translator, const char * _memberName, ParentExtract * _parentExtract, EvalContext * _parent, IHqlExpression * _colocal, BuildCtx & createctx, BuildCtx & startctx)
  1477. : ClassEvalContext(_translator, _parentExtract, _parent, createctx, startctx)
  1478. {
  1479. colocalMember.set(_colocal);
  1480. helpersExist = false;
  1481. memberName.set(_memberName);
  1482. }
  1483. IHqlExpression * NestedEvalContext::createGraphLookup(unique_id_t id, bool isChild)
  1484. {
  1485. ensureHelpersExist();
  1486. return translator.doCreateGraphLookup(onCreate.declarectx, onCreate.childctx, id, "activity", isChild);
  1487. }
  1488. void NestedEvalContext::ensureHelpersExist()
  1489. {
  1490. if (!helpersExist)
  1491. {
  1492. if (parent)
  1493. parent->ensureHelpersExist();
  1494. StringBuffer s;
  1495. ActivityInstance * rootActivity = queryActivity();
  1496. //void onStart(ICodeContext * _ctx, <ActivityClass> * _activity)
  1497. BuildCtx oncreatectx(onCreate.declarectx);
  1498. oncreatectx.addQuotedCompound(s.clear().append("inline void onCreate(ICodeContext * _ctx, ").append(rootActivity->className).append(" * _activity)"));
  1499. oncreatectx.addQuoted(s.clear().append("activity = _activity;"));
  1500. oncreatectx.addQuoted("ctx = _ctx;");
  1501. onCreate.declarectx.addQuoted("ICodeContext * ctx;");
  1502. onCreate.declarectx.addQuoted(s.clear().append(rootActivity->className).append(" * activity;"));
  1503. onCreate.declarectx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  1504. onCreate.createFunctionStructure(translator, oncreatectx, false, NULL);
  1505. //void onStart(const byte * parentExtract)
  1506. BuildCtx onstartctx(onStart.declarectx);
  1507. if (requiresOnStart())
  1508. {
  1509. onstartctx.addQuotedCompound("inline void onStart()");
  1510. if (parentExtract)
  1511. parentExtract->beginChildActivity(onStart.declarectx, onstartctx, GraphCoLocal, colocalMember, true, parentExtract->canSerializeFields(), NULL);
  1512. onstartctx.associateExpr(insideOnStartMarker, NULL);
  1513. onStart.createFunctionStructure(translator, onstartctx, false, NULL);
  1514. }
  1515. parent->callNestedHelpers(memberName);
  1516. helpersExist = true;
  1517. }
  1518. }
  1519. void NestedEvalContext::initContext()
  1520. {
  1521. if (requiresOnStart())
  1522. ensureHelpersExist();
  1523. else if (parentExtract && parentExtract->canSerializeFields())
  1524. {
  1525. ensureHelpersExist();
  1526. parentExtract->associateCursors(onStart.declarectx, onStart.declarectx, GraphCoLocal);
  1527. }
  1528. }
  1529. bool NestedEvalContext::evaluateInParent(BuildCtx & ctx, IHqlExpression * expr, bool hasOnStart)
  1530. {
  1531. //This is a bit ugly. Latter condition is to cope with group aggregate callbacks
  1532. return parent->isRowInvariant(expr) || parentExtract->canEvaluate(expr);
  1533. }
  1534. void NestedEvalContext::callNestedHelpers(const char * member)
  1535. {
  1536. doCallNestedHelpers(member, "activity");
  1537. }
  1538. //---------------------------------------------------------------------------
  1539. MemberEvalContext::MemberEvalContext(HqlCppTranslator & _translator, ParentExtract * _parentExtract, EvalContext * _parent, BuildCtx & _ctx)
  1540. : EvalContext(_translator, _parentExtract, _parent), ctx(_ctx)
  1541. {
  1542. assertex(parent);
  1543. colocalMember.set(colocalSameClassPreserveExpr);
  1544. }
  1545. void MemberEvalContext::callNestedHelpers(const char * member)
  1546. {
  1547. parent->callNestedHelpers(member);
  1548. }
  1549. IHqlExpression * MemberEvalContext::createGraphLookup(unique_id_t id, bool isChild)
  1550. {
  1551. return parent->createGraphLookup(id, isChild);
  1552. }
  1553. AliasKind MemberEvalContext::evaluateExpression(BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt, bool evaluateLocally)
  1554. {
  1555. return parentExtract->evaluateExpression(ctx, value, tgt, colocalMember, evaluateLocally);
  1556. }
  1557. bool MemberEvalContext::isRowInvariant(IHqlExpression * expr)
  1558. {
  1559. return translator.canEvaluateInContext(ctx, expr);
  1560. }
  1561. void MemberEvalContext::ensureHelpersExist()
  1562. {
  1563. parent->ensureHelpersExist();
  1564. }
  1565. void MemberEvalContext::initContext()
  1566. {
  1567. parentExtract->associateCursors(ctx, ctx, GraphCoLocal);
  1568. }
  1569. bool MemberEvalContext::getInvariantMemberContext(BuildCtx * ctx, BuildCtx * * declarectx, BuildCtx * * initctx, bool isIndependentMaybeShared, bool invariantEachStart)
  1570. {
  1571. return parent->getInvariantMemberContext(ctx, declarectx, initctx, isIndependentMaybeShared, invariantEachStart);
  1572. }
  1573. void MemberEvalContext::tempCompatiablityEnsureSerialized(const CHqlBoundTarget & tgt)
  1574. {
  1575. parent->tempCompatiablityEnsureSerialized(tgt);
  1576. }
  1577. //---------------------------------------------------------------------------
  1578. void HqlCppTranslator::ensureContextAvailable(BuildCtx & ctx)
  1579. {
  1580. EvalContext * instance = queryEvalContext(ctx);
  1581. if (instance)
  1582. instance->ensureContextAvailable();
  1583. }
  1584. /*
  1585. The following is the structure that we are going to generate in the C++ for an activity
  1586. <<xx>> marks a context that is preserved
  1587. virtual void onCreate(ICodeContext * _ctx, IHThorArg * _colocal, MemoryBuffer * in) {
  1588. colocal = (c2*)_colocal;
  1589. ctx = _ctx;
  1590. <<onCreate.clonectx>>
  1591. // clone values from colocal-> into local variables.
  1592. if (in) {
  1593. //deserialize any values from
  1594. <<onCreate.deserializectx>>
  1595. }
  1596. else {
  1597. //evaluate any query-invariant values.
  1598. <<onCreate.evalctx>>
  1599. }
  1600. <<onCreate.childctx>>
  1601. // create graph lookups.
  1602. nestedObject.onCreate(ctx, this);
  1603. }
  1604. virtual void serializeCreateContext(MemoryBuffer & out) {
  1605. //serialize any query-invariant values
  1606. }
  1607. virtual void onStart(const byte * pe) {
  1608. extractVar = (byte *)pe;
  1609. <<onStart.clonectx>>
  1610. <<onStart.evalctx>>
  1611. <<onStart.childctx>>
  1612. nestedObject.onStart(pe);
  1613. }
  1614. NestedClass:
  1615. void onCreate(ICodeContext * _ctx, cH * _activity) {
  1616. activity = _activity;
  1617. ctx = _ctx;
  1618. <<onCreate.clonectx>>
  1619. <<onCreate.childctx>>
  1620. //clone values from parent class into this class
  1621. }
  1622. virtual void onStart(const byte * pe) {
  1623. extractVar = (byte *)pe; //This means that all values retrieved from the extract have the same format in the nested class
  1624. <<onStart.clonectx>>
  1625. <<onStart.childctx>>
  1626. }
  1627. virtual void onCreate(ICodeContext * _ctx, IHThorArg * _colocal) {
  1628. colocal = (c2*)_colocal;
  1629. ctx = _ctx;
  1630. <<onCreate.clonectx>>
  1631. // clone values from colocal-> into local variables.
  1632. <<onCreate.evalctx>>
  1633. // evaluate graph invariant expressions
  1634. //local graph lookups
  1635. commonCreate();
  1636. }
  1637. inline void commonCreate()
  1638. <<onCreate.childctx>>
  1639. // create child graph lookups.
  1640. // nestedObject.onCreate(ctx, this);
  1641. }
  1642. virtual void serializeContext(MemoryBuffer & out) {
  1643. //serialize any query-invariant values
  1644. }
  1645. virtual void onStart(const byte * pe) {
  1646. extractVar = (byte *)pe;
  1647. <<onStart.clonectx>>
  1648. <<onStart.evalctx>>
  1649. <<onStart.childctx>>
  1650. }
  1651. inline void commonOnStart()
  1652. {
  1653. nestedObject.onStart(pe);
  1654. }
  1655. virtual void onCreateStart(ICodeContext * _ctx, MemoryBuffer * in, const byte * pe)
  1656. {
  1657. ctx = _ctx;
  1658. colocal = NULL;
  1659. <<onCreate.deserialize>>
  1660. commonCreate();
  1661. extractVar = (byte *)pe;
  1662. commonOnStart();
  1663. }
  1664. xxx.clonectx - The point where members are cloned from colocal parent activities and parent classes.
  1665. xxx.evalctx - The point where anything that needs to be evaluated is placed.
  1666. Notes on onCreate/onStart
  1667. a) onStart needs to be created/called for child activities (and their nested classes) in order to bind the variables correctly.
  1668. b) onCreate needs to be called for nested classes in order to access grand parent colocal extracts.
  1669. c) If a function is created it needs to be called from parent (which stops us using compoundOpt unless the base class contains a default implementation)
  1670. d) We don't want to call onCReate() + onStart all the time because it generates lots of extra code.
  1671. =>
  1672. 1) For any child class (activity or nested) we always generate + call them even if they don't have any extra code.
  1673. 2) For nested classes of top level activities the functions are generated and called when something is added that needs it.
  1674. Notes
  1675. * Serialization + evaluation of expressions
  1676. a) if an activity is not executed remotely there is no need to serialize on Create
  1677. => serialize remote roxie activites
  1678. => serialize remote thor child activities.
  1679. => optionally serialize all root thor activities depending on whether Jake makes use of it.
  1680. => add a debug flag to force serialization for the purpose of testing.
  1681. b) table-invariant values.
  1682. => evaluated once in the onCreate() of the activity. Not retrieved from a parent activity.
  1683. c) row invariant values
  1684. => if a value can be evaluated in a parent extract context then it is evaluated there, and
  1685. then cloned/serialized into the current context.
  1686. d) since row invariant values are calulated in the parent context there is nothing to be gained from serializing the
  1687. start context. => Remove the code + methods from the eclagent helper definition.
  1688. e) Nested class values.
  1689. These are always evaluated in the parent context, and then cloned into the current class.
  1690. - The extracts from all parent colocal activities are cloned into the child activity
  1691. - All members from a parent activity are copied into members in the current activity + accessed from there.
  1692. [This is partly to simplify the access expressions from colocal children]
  1693. Evaluation of expressions:
  1694. o Table-invariant
  1695. - Do in the onCreate of the activity.
  1696. - Could also serialize from parent to child queries, so only evaluated once.
  1697. = Trade off between re-eveluation and cloning/extra data serialized to child query.
  1698. o Other expressions
  1699. - Each expression has a minimal level it can be evaluated at.
  1700. - main decision is whether to evaluate in the parent's build ctx, or in a local onStart()
  1701. = If there is no onStart, then always evaluate in parent build ctx.
  1702. = If there is an onStart, then you are trading off the cost of serializing the values required to compute
  1703. the expression, and possibly multiple evaluations, against the cost of serializing the expression.
  1704. - For non-local always evaluate in the parent build ctx.
  1705. - For colocal, it is debatable - I'll add as a flag.
  1706. o non-local
  1707. o COUNTER, MATCHTEXT, XMLTEXT, FAILCODE/FAILMESSAGE
  1708. - These are all context dependent in different ways.
  1709. - They all need to be evaluated in the correct context (not too deep or too shallow)
  1710. - Simplest is to evaluate any expression that contains them at the deepest level, and actual expressions evaluated
  1711. at higher levels.
  1712. Activity
  1713. Invariant: evaluate in onCreateContext
  1714. Nested
  1715. Evaluate in parent. If
  1716. General
  1717. * see codegen.txt for more details.
  1718. */