hqlinline.cpp 69 KB

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