hqllib.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  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 "jhash.hpp"
  19. #include "jmisc.hpp"
  20. #include "jstream.ipp"
  21. #include "jdebug.hpp"
  22. #include "hql.hpp"
  23. #include "hqlattr.hpp"
  24. #include "hqlfold.hpp"
  25. #include "hqlthql.hpp"
  26. #include "hqltrans.ipp"
  27. #include "hqlutil.hpp"
  28. #include "hqlcpp.ipp"
  29. #include "hqlcatom.hpp"
  30. #include "hqlcpputil.hpp"
  31. #include "hqlgraph.ipp"
  32. #include "hqllib.ipp"
  33. #include "hqlwcpp.hpp"
  34. #include "hqlttcpp.ipp"
  35. #include "hqlinline.hpp"
  36. static IHqlExpression * queryLibraryInputSequence(IHqlExpression * expr)
  37. {
  38. IHqlExpression * arg = expr->queryChild(0);
  39. if (arg->isRecord())
  40. arg = expr->queryChild(1);
  41. return arg;
  42. }
  43. HqlCppLibrary::HqlCppLibrary(HqlCppTranslator & _translator, IHqlExpression * libraryInterface, ClusterType _clusterType) : translator(_translator), inputMapper(libraryInterface), clusterType(_clusterType)
  44. {
  45. assertex(libraryInterface->getOperator() == no_funcdef);
  46. scopeExpr = libraryInterface->queryChild(0);
  47. assertex(scopeExpr->getOperator() == no_virtualscope);
  48. streamedCount = 0;
  49. if (clusterType != HThorCluster)
  50. streamedCount = inputMapper.numStreamedInputs();
  51. extractOutputs();
  52. }
  53. void HqlCppLibrary::extractOutputs()
  54. {
  55. HqlExprArray symbols;
  56. scopeExpr->queryScope()->getSymbols(symbols);
  57. IHqlScope * scope = scopeExpr->queryScope();
  58. HqlDummyLookupContext dummyctx(NULL);
  59. ForEachItemIn(i, symbols)
  60. {
  61. IHqlExpression & cur = symbols.item(i);
  62. if (isExported(&cur))
  63. {
  64. _ATOM name = cur.queryName();
  65. OwnedHqlExpr value = scope->lookupSymbol(name, LSFpublic, dummyctx);
  66. if (value && !value->isFunction())
  67. {
  68. if (value->isDataset() || value->isDatarow() || value->queryType()->isScalar())
  69. {
  70. OwnedHqlExpr null = createNullExpr(value);
  71. outputs.append(*cur.cloneAllAnnotations(null));
  72. }
  73. }
  74. }
  75. }
  76. outputs.sort(compareSymbolsByName);
  77. }
  78. unsigned HqlCppLibrary::getInterfaceHash() const
  79. {
  80. unsigned crc = getHash(outputs, 0x12345678); // only hashes type and name, not implementation
  81. crc = getHash(inputMapper.queryRealParameters(), crc);
  82. if (translator.queryOptions().implicitLinkedChildRows)
  83. crc ^= 0x456271;
  84. if (crc == 0) crc = 0x87654321; // ensure it is non zero.
  85. return crc;
  86. }
  87. unsigned HqlCppLibrary::getHash(const HqlExprArray & values, unsigned crc) const
  88. {
  89. unsigned num = values.ordinality();
  90. crc = hashc((const byte *)&num, sizeof(num), crc);
  91. ForEachItemIn(i, values)
  92. {
  93. IHqlExpression & cur = values.item(i);
  94. //names are significant because inputs/outputs are ordered by name
  95. const char * name = cur.queryName()->str();
  96. crc = hashnc((const byte *)name, strlen(name), crc);
  97. ITypeInfo * type = cur.queryType();
  98. byte tc = type->getTypeCode();
  99. switch (tc)
  100. {
  101. case type_record:
  102. case type_row:
  103. case type_table:
  104. case type_groupedtable:
  105. {
  106. OwnedHqlExpr normalizedRecord = normalizeRecord(translator, cur.queryRecord());
  107. OwnedHqlExpr serialized = getSerializedForm(normalizedRecord);
  108. unsigned recordCrc = getExpressionCRC(serialized);
  109. crc = hashc((const byte *)&tc, sizeof(tc), crc);
  110. crc = hashc((const byte *)&recordCrc, sizeof(recordCrc), crc);
  111. break;
  112. }
  113. default:
  114. {
  115. size32_t size = type->getSize();
  116. crc = hashc((const byte *)&tc, sizeof(tc), crc);
  117. crc = hashc((const byte *)&size, sizeof(size), crc);
  118. break;
  119. }
  120. }
  121. }
  122. return crc;
  123. }
  124. unsigned HqlCppLibrary::queryOutputIndex(_ATOM name) const
  125. {
  126. ForEachItemIn(i, outputs)
  127. {
  128. if (outputs.item(i).queryName() == name)
  129. return i;
  130. }
  131. return NotFound;
  132. }
  133. HqlCppLibraryImplementation::HqlCppLibraryImplementation(HqlCppTranslator & _translator, IHqlExpression * libraryInterface, IHqlExpression * _libraryId, ClusterType _clusterType)
  134. : HqlCppLibrary(_translator, libraryInterface, _clusterType), libraryId(_libraryId)
  135. {
  136. inputMapper.mapRealToLogical(inputExprs, logicalParams, libraryId, (clusterType != HThorCluster), translator.targetThor());
  137. }
  138. HqlCppLibraryInstance::HqlCppLibraryInstance(HqlCppTranslator & translator, IHqlExpression * _instanceExpr, ClusterType clusterType) : instanceExpr(_instanceExpr)
  139. {
  140. assertex(instanceExpr->getOperator() == no_libraryscopeinstance);
  141. libraryFuncdef = instanceExpr->queryDefinition();
  142. assertex(libraryFuncdef->getOperator() == no_funcdef);
  143. IHqlExpression * libraryScope = libraryFuncdef->queryChild(0);
  144. assertex(libraryScope->getOperator() == no_libraryscope);
  145. IHqlExpression * libraryInterface = queryPropertyChild(libraryScope, implementsAtom, 0);
  146. assertex(libraryInterface);
  147. library.setown(new HqlCppLibrary(translator, libraryInterface, clusterType));
  148. assertex(library->totalInputs() == (libraryFuncdef->queryChild(1)->numChildren()));
  149. }
  150. //---------------------------------------------------------------------------
  151. static HqlTransformerInfo hqlLibraryTransformerInfo("HqlLibraryTransformer");
  152. class HqlLibraryTransformer: public QuickHqlTransformer
  153. {
  154. public:
  155. HqlLibraryTransformer(IConstWorkUnit * _wu, bool _isLibrary)
  156. : QuickHqlTransformer(hqlLibraryTransformerInfo, NULL), wu(_wu)
  157. {
  158. ignoreFirstScope = _isLibrary;
  159. }
  160. IHqlExpression * doTransformLibrarySelect(IHqlExpression * expr)
  161. {
  162. //Map the new attribute
  163. IHqlExpression * oldModule = expr->queryChild(1);
  164. OwnedHqlExpr newModule = transform(oldModule);
  165. if (oldModule == newModule)
  166. return LINK(expr);
  167. _ATOM attrName = expr->queryChild(3)->queryName();
  168. HqlDummyLookupContext dummyctx(NULL);
  169. OwnedHqlExpr value = newModule->queryScope()->lookupSymbol(attrName, makeLookupFlags(true, expr->hasProperty(ignoreBaseAtom), false), dummyctx);
  170. assertex(value != NULL);
  171. IHqlExpression * oldAttr = expr->queryChild(2);
  172. if (oldAttr->isDataset() || oldAttr->isDatarow())
  173. return value.getClear();
  174. assertex(value->isDataset());
  175. IHqlExpression * field = value->queryRecord()->queryChild(0);
  176. OwnedHqlExpr select = createRow(no_selectnth, value.getClear(), createConstantOne());
  177. return createSelectExpr(select.getClear(), LINK(field)); // no newAtom because not normalised yet
  178. }
  179. virtual IHqlExpression * createTransformedBody(IHqlExpression * expr)
  180. {
  181. switch (expr->getOperator())
  182. {
  183. case no_libraryselect:
  184. return doTransformLibrarySelect(expr);
  185. }
  186. return QuickHqlTransformer::createTransformedBody(expr);
  187. }
  188. protected:
  189. IHqlExpression * createSimplifiedLibrary(IHqlExpression * libraryExpr)
  190. {
  191. IHqlScope * oldScope = libraryExpr->queryScope();
  192. IHqlScope * lookupScope = oldScope;
  193. IHqlExpression * interfaceExpr = queryPropertyChild(libraryExpr, implementsAtom, 0);
  194. if (interfaceExpr)
  195. lookupScope = interfaceExpr->queryScope();
  196. HqlExprArray symbols, newSymbols;
  197. lookupScope->getSymbols(symbols);
  198. HqlDummyLookupContext dummyctx(NULL);
  199. ForEachItemIn(i, symbols)
  200. {
  201. IHqlExpression & cur = symbols.item(i);
  202. if (isExported(&cur))
  203. {
  204. _ATOM name = cur.queryName();
  205. OwnedHqlExpr oldSymbol = oldScope->lookupSymbol(name, LSFpublic, dummyctx);
  206. OwnedHqlExpr newValue;
  207. ITypeInfo * type = oldSymbol->queryType();
  208. if (oldSymbol->isDataset() || oldSymbol->isDatarow())
  209. {
  210. newValue.setown(createNullExpr(oldSymbol));
  211. }
  212. else
  213. {
  214. //Convert a scalar to a select from a dataset
  215. OwnedHqlExpr field = createField(unknownAtom, LINK(type), NULL, NULL);
  216. OwnedHqlExpr newRecord = createRecord(field);
  217. OwnedHqlExpr ds = createDataset(no_null, LINK(newRecord));
  218. newValue.setown(createNullExpr(ds));
  219. }
  220. if (oldSymbol->isFunction())
  221. {
  222. // Should have been caught in the parser.. Following code should be correct if we ever work out how to implement
  223. throwUnexpected();
  224. HqlExprArray parms;
  225. unwindChildren(parms, oldSymbol, 1);
  226. IHqlExpression * formals = createSortList(parms);
  227. newValue.setown(createFunctionDefinition(name, newValue.getClear(), formals, NULL, NULL));
  228. }
  229. IHqlExpression * newSym = oldSymbol->cloneAllAnnotations(newValue);
  230. newSymbols.append(*newSym);
  231. }
  232. }
  233. HqlExprArray children;
  234. unwindChildren(children, libraryExpr);
  235. return queryExpression(oldScope->clone(children, newSymbols));
  236. }
  237. protected:
  238. IConstWorkUnit * wu;
  239. bool ignoreFirstScope;
  240. };
  241. class HqlEmbeddedLibraryTransformer: public HqlLibraryTransformer
  242. {
  243. public:
  244. HqlEmbeddedLibraryTransformer(IConstWorkUnit * _wu, HqlExprArray & _internalLibraries, bool _isLibrary)
  245. : HqlLibraryTransformer(_wu, _isLibrary), internalLibraries(_internalLibraries)
  246. {
  247. }
  248. virtual IHqlExpression * createTransformedBody(IHqlExpression * expr)
  249. {
  250. switch (expr->getOperator())
  251. {
  252. case no_libraryscopeinstance:
  253. {
  254. IHqlExpression * scopeFunc = expr->queryDefinition();
  255. assertex(scopeFunc->getOperator() == no_funcdef);
  256. IHqlExpression * moduleExpr = scopeFunc->queryChild(0);
  257. assertex(moduleExpr->getOperator() == no_libraryscope);
  258. IHqlExpression * internalExpr = moduleExpr->queryProperty(internalAtom);
  259. if (internalExpr)
  260. {
  261. IHqlExpression * nameExpr = moduleExpr->queryProperty(nameAtom);
  262. if (!matchedInternalLibraries.contains(*nameExpr))
  263. {
  264. internalLibraries.append(*transformEmbeddedLibrary(scopeFunc));
  265. matchedInternalLibraries.append(*LINK(nameExpr));
  266. }
  267. //remove the parameter from the internal attribute from the module that is being called.
  268. //so save in subsequent translation
  269. OwnedHqlExpr newModuleExpr = replaceOwnedProperty(moduleExpr, createAttribute(internalAtom));
  270. OwnedHqlExpr newScopeFunc = replaceChild(scopeFunc, 0, newModuleExpr);
  271. HqlExprArray instanceArgs;
  272. unwindChildren(instanceArgs, expr);
  273. return createLibraryInstance(LINK(newScopeFunc), instanceArgs);
  274. }
  275. else
  276. return LINK(expr);
  277. //otherwise already transformed....
  278. break;
  279. }
  280. case no_libraryscope:
  281. if (!ignoreFirstScope)
  282. {
  283. //Now create a simplified no_library scope with null values for each of the values of the exported symbols
  284. //Don't walk contents because that is an implementation detail, which could change
  285. return createSimplifiedLibrary(expr);
  286. }
  287. ignoreFirstScope = false;
  288. break;
  289. }
  290. return HqlLibraryTransformer::createTransformedBody(expr);
  291. }
  292. IHqlExpression * transformEmbeddedLibrary(IHqlExpression * expr)
  293. {
  294. //avoid special casing above
  295. assertex(expr->getOperator() == no_funcdef);
  296. IHqlExpression * library = expr->queryChild(0);
  297. HqlExprArray args;
  298. args.append(*QuickHqlTransformer::createTransformedBody(library));
  299. unwindChildren(args, expr, 1);
  300. return expr->clone(args);
  301. }
  302. protected:
  303. HqlExprArray & internalLibraries;
  304. HqlExprArray matchedInternalLibraries;
  305. };
  306. //---------------------------------------------------------------------------
  307. void HqlCppTranslator::processEmbeddedLibraries(HqlExprArray & exprs, HqlExprArray & internalLibraries, bool isLibrary)
  308. {
  309. HqlExprArray transformed;
  310. HqlEmbeddedLibraryTransformer transformer(wu(), internalLibraries, isLibrary);
  311. ForEachItemIn(i, exprs)
  312. transformed.append(*transformer.transform(&exprs.item(i)));
  313. replaceArray(exprs, transformed);
  314. }
  315. //---------------------------------------------------------------------------
  316. static IHqlExpression * splitSelect(IHqlExpression * & rootDataset, IHqlExpression * expr, IHqlExpression * selSeq)
  317. {
  318. assertex(expr->getOperator() == no_select);
  319. IHqlExpression * ds = expr->queryChild(0);
  320. IHqlExpression * field = expr->queryChild(1);
  321. IHqlExpression * attrSelector;
  322. if (ds->isDatarow() && (ds->getOperator() == no_select))
  323. {
  324. attrSelector = splitSelect(rootDataset, ds, selSeq);
  325. }
  326. else
  327. {
  328. rootDataset = ds;
  329. attrSelector = createSelector(no_left, ds, selSeq);
  330. }
  331. return createSelectExpr(attrSelector, LINK(field));
  332. }
  333. static IHqlExpression * convertScalarToDataset(IHqlExpression * expr)
  334. {
  335. switch (expr->getOperator())
  336. {
  337. case NO_AGGREGATE:
  338. return convertScalarAggregateToDataset(expr);
  339. case no_select:
  340. {
  341. //Project dataset down to a single field...
  342. IHqlExpression * ds;
  343. OwnedHqlExpr selSeq = createSelectorSequence();
  344. OwnedHqlExpr newExpr = splitSelect(ds, expr, selSeq);
  345. IHqlExpression * field = expr->queryChild(1);
  346. OwnedHqlExpr record = createRecord(field);
  347. OwnedHqlExpr assign = createAssign(createSelectExpr(createSelector(no_self, record, NULL), LINK(field)), LINK(newExpr));
  348. OwnedHqlExpr row = createRow(no_projectrow, LINK(ds), createComma(createValue(no_transform, makeTransformType(record->getType()), LINK(assign)), LINK(selSeq)));
  349. return LINK(row);
  350. //Following is more strictly correct, but messes up the resourcing.
  351. //return createDatasetFromRow(LINK(row));
  352. }
  353. break;
  354. }
  355. OwnedHqlExpr field = createField(valueAtom, expr->getType(), NULL, NULL);
  356. OwnedHqlExpr record = createRecord(field);
  357. OwnedHqlExpr assign = createAssign(createSelectExpr(createSelector(no_self, record, NULL), LINK(field)), LINK(expr));
  358. OwnedHqlExpr row = createRow(no_createrow, createValue(no_transform, makeTransformType(record->getType()), LINK(assign)));
  359. return createDatasetFromRow(LINK(row));
  360. }
  361. void HqlCppLibraryImplementation::mapLogicalToImplementation(HqlExprArray & exprs, IHqlExpression * libraryExpr)
  362. {
  363. //First replace parameters with streamed inputs, and no_libraryinputs, by creating some psuedo-arguments,
  364. //and then binding them.
  365. HqlExprArray actuals;
  366. appendArray(actuals, logicalParams);
  367. OwnedHqlExpr bound = createBoundFunction(NULL, libraryExpr, actuals, NULL, true);
  368. IHqlScope * scope = bound->queryScope();
  369. assertex(scope);
  370. //Now resolve each of the outputs in the transformed module
  371. HqlDummyLookupContext dummyctx(NULL);
  372. unsigned numInputs = numStreamedInputs();
  373. ForEachItemIn(i, outputs)
  374. {
  375. IHqlExpression & curOutput = outputs.item(i);
  376. OwnedHqlExpr output = scope->lookupSymbol(curOutput.queryName(), LSFpublic, dummyctx);
  377. // Do a global replace of input(n) with no_getgraphresult(n), and no_param with no_
  378. if (!output->isDatarow() && !output->isDataset())
  379. output.setown(convertScalarToDataset(output));
  380. HqlExprArray args;
  381. args.append(*LINK(output));
  382. args.append(*LINK(libraryId));
  383. args.append(*getSizetConstant(i+numInputs));
  384. exprs.append(*createValue(no_setgraphresult, makeVoidType(), args));
  385. }
  386. }
  387. //---------------------------------------------------------------------------
  388. void ThorBoundLibraryActivity::noteOutputUsed(_ATOM name)
  389. {
  390. unsigned matchIndex = libraryInstance->library->queryOutputIndex(name);
  391. assertex(matchIndex != NotFound);
  392. addGraphAttributeInt(graphNode, "_outputUsed", matchIndex);
  393. }
  394. ABoundActivity * HqlCppTranslator::doBuildActivityLibrarySelect(BuildCtx & ctx, IHqlExpression * expr)
  395. {
  396. IHqlExpression * module = expr->queryChild(1);
  397. ThorBoundLibraryActivity * callInstance = static_cast<ThorBoundLibraryActivity *>(buildCachedActivity(ctx, module));
  398. callInstance->noteOutputUsed(expr->queryChild(3)->queryName());
  399. return callInstance;
  400. }
  401. //---------------------------------------------------------------------------
  402. void HqlCppTranslator::buildLibraryInstanceExtract(BuildCtx & ctx, HqlCppLibraryInstance * libraryInstance)
  403. {
  404. BuildCtx subctx(ctx);
  405. subctx.addQuotedCompound("virtual void createParentExtract(rtlRowBuilder & builder)");
  406. BuildCtx beforeBuilderCtx(subctx);
  407. beforeBuilderCtx.addGroup();
  408. Owned<ParentExtract> extractBuilder = createExtractBuilder(subctx, PETlibrary, NULL, GraphNonLocal, false);
  409. StringBuffer s;
  410. s.append("rtlRowBuilder & ");
  411. generateExprCpp(s, extractBuilder->queryExtractName());
  412. s.append(" = builder;");
  413. beforeBuilderCtx.addQuoted(s);
  414. beginExtract(subctx, extractBuilder);
  415. //Ensure all the values are added to the serialization in the correct order
  416. CHqlBoundExpr dummyTarget;
  417. unsigned numParams = libraryInstance->numParameters();
  418. for (unsigned i2 = libraryInstance->numStreamedInputs(); i2 < numParams; i2++)
  419. {
  420. IHqlExpression * parameter = libraryInstance->queryParameter(i2);
  421. extractBuilder->addSerializedExpression(libraryInstance->queryActual(i2), parameter->queryType());
  422. }
  423. endExtract(subctx, extractBuilder);
  424. }
  425. ABoundActivity * HqlCppTranslator::doBuildActivityLibraryInstance(BuildCtx & ctx, IHqlExpression * expr)
  426. {
  427. Owned<HqlCppLibraryInstance> libraryInstance = new HqlCppLibraryInstance(*this, expr, targetClusterType);
  428. CIArray boundInputs;
  429. unsigned numStreamed = libraryInstance->numStreamedInputs();
  430. for (unsigned i1=0; i1 < numStreamed; i1++)
  431. boundInputs.append(*buildCachedActivity(ctx, libraryInstance->queryActual(i1)));
  432. IHqlExpression * moduleFunction = expr->queryDefinition(); // no_funcdef
  433. IHqlExpression * module = moduleFunction->queryChild(0);
  434. assertex(module->getOperator() == no_libraryscope);
  435. IHqlExpression * nameAttr = module->queryProperty(nameAtom);
  436. OwnedHqlExpr name = foldHqlExpression(nameAttr->queryChild(0));
  437. IValue * nameValue = name->queryValue();
  438. IHqlExpression * originalName = queryPropertyChild(module, _original_Atom, 0);
  439. StringBuffer libraryName;
  440. if (nameValue)
  441. nameValue->getStringValue(libraryName);
  442. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKlibrarycall, expr, "LibraryCall");
  443. StringBuffer graphLabel;
  444. if (originalName)
  445. {
  446. StringBuffer temp;
  447. temp.append(originalName->queryName()).toLowerCase();
  448. graphLabel.append("Library").newline().append(temp);
  449. }
  450. else if (nameValue)
  451. graphLabel.append("Library").newline().append(libraryName);
  452. if (graphLabel.length())
  453. instance->graphLabel.set(graphLabel.str());
  454. buildActivityFramework(instance);
  455. buildInstancePrefix(instance);
  456. buildLibraryInstanceExtract(instance->startctx, libraryInstance);
  457. //MORE: Need to call functions to add the extract
  458. const HqlCppLibrary * library = libraryInstance->library;
  459. if (nameValue)
  460. {
  461. instance->addAttribute("libname", libraryName.str());
  462. Owned<IWULibrary> wulib = wu()->updateLibraryByName(libraryName.str());
  463. wulib->addActivity((unsigned)instance->activityId);
  464. }
  465. instance->addAttributeInt("_interfaceHash", library->getInterfaceHash());
  466. instance->addAttributeBool("embedded", module->hasProperty(internalAtom));
  467. instance->addAttributeInt("_maxOutputs", library->outputs.ordinality());
  468. if (!targetHThor())
  469. instance->addAttributeInt("_graphid", nextActivityId()); // reserve an id...
  470. // A debugging option to make it clearer how a library is being called.
  471. if (options.addLibraryInputsToGraph)
  472. {
  473. unsigned numParams = libraryInstance->numParameters();
  474. for (unsigned iIn = 0; iIn < numParams; iIn++)
  475. {
  476. IHqlExpression * parameter = libraryInstance->queryParameter(iIn);
  477. StringBuffer paramName;
  478. StringBuffer paramEcl;
  479. paramName.append("input").append(iIn).append("__").append(parameter->queryName());
  480. toECL(libraryInstance->queryActual(iIn), paramEcl, false, true);
  481. instance->addAttribute(paramName, paramEcl);
  482. }
  483. }
  484. StringBuffer s;
  485. BuildCtx metactx(instance->classctx);
  486. metactx.addQuotedCompound("virtual IOutputMetaData * queryOutputMeta(unsigned whichOutput)");
  487. BuildCtx switchctx(metactx);
  488. switchctx.addQuotedCompound("switch (whichOutput)");
  489. HqlDummyLookupContext dummyCtx(NULL);
  490. IHqlScope * moduleScope = module->queryScope();
  491. ForEachItemIn(iout, library->outputs)
  492. {
  493. IHqlExpression & cur = library->outputs.item(iout);
  494. OwnedHqlExpr dataset = moduleScope->lookupSymbol(cur.queryName(), LSFpublic, dummyCtx);
  495. assertex(dataset && dataset->queryRecord());
  496. MetaInstance meta(*this, dataset->queryRecord(), isGrouped(dataset));
  497. buildMetaInfo(meta);
  498. switchctx.addQuoted(s.clear().append("case ").append(iout).append(": return &").append(meta.queryInstanceObject()).append(";"));
  499. }
  500. metactx.addReturn(queryQuotedNullExpr());
  501. //Library Name must be onCreate invariant
  502. BuildCtx namectx(instance->createctx);
  503. namectx.addQuotedCompound("virtual char * getLibraryName()");
  504. buildReturn(namectx, name, unknownVarStringType);
  505. buildInstanceSuffix(instance);
  506. ForEachItemIn(idx2, boundInputs)
  507. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&boundInputs.item(idx2), 0, idx2);
  508. Owned<ABoundActivity> boundInstance = instance->getBoundActivity();
  509. return new ThorBoundLibraryActivity(boundInstance, instance->graphNode, libraryInstance);
  510. }
  511. void HqlCppTranslator::buildLibraryGraph(BuildCtx & ctx, IHqlExpression * expr, const char * graphName)
  512. {
  513. OwnedHqlExpr resourced = getResourcedGraph(expr->queryChild(0), NULL);
  514. beginGraph(graphName);
  515. traceExpression("beforeGenerate", resourced);
  516. BuildCtx initctx(ctx);
  517. initctx.addGroup();
  518. initctx.addFilter(queryBoolExpr(false));
  519. Owned<LibraryEvalContext> libraryContext = new LibraryEvalContext(*this);
  520. initctx.associate(*libraryContext);
  521. unsigned numParams = outputLibrary->totalInputs();
  522. for (unsigned i1 = outputLibrary->numStreamedInputs(); i1 < numParams; i1++)
  523. {
  524. IHqlExpression & parameter = *outputLibrary->queryInputExpr(i1);
  525. libraryContext->associateExpression(initctx, &parameter);
  526. }
  527. Owned<ParentExtract> extractBuilder = createExtractBuilder(initctx, PETlibrary, outputLibraryId, GraphRemote, false);
  528. beginExtract(initctx, extractBuilder);
  529. BuildCtx evalctx(ctx);
  530. evalctx.addGroup();
  531. evalctx.addFilter(queryBoolExpr(false));
  532. //Ensure all the values are added to the serialization in the correct order by creating a dummy context and then
  533. //evaluating each parameter in term. Slightly ugly - it would be better using different calls.
  534. extractBuilder->associateCursors(evalctx, evalctx, GraphNonLocal);
  535. CHqlBoundExpr dummyTarget;
  536. for (unsigned i2 = outputLibrary->numStreamedInputs(); i2 < numParams; i2++)
  537. {
  538. IHqlExpression * parameter = outputLibrary->queryInputExpr(i2);
  539. extractBuilder->evaluateExpression(evalctx, parameter, dummyTarget, NULL, false);
  540. }
  541. BuildCtx graphctx(initctx);
  542. activeGraphCtx = &ctx;
  543. doBuildThorSubGraph(graphctx, resourced, SubGraphRoot, (unsigned)getIntValue(outputLibraryId->queryChild(0)), outputLibraryId);
  544. activeGraphCtx = NULL;
  545. endExtract(initctx, extractBuilder);
  546. endGraph();
  547. }
  548. //---------------------------------------------------------------------------
  549. LibraryEvalContext::LibraryEvalContext(HqlCppTranslator & _translator) : EvalContext(_translator, NULL, NULL)
  550. {
  551. }
  552. AliasKind LibraryEvalContext::evaluateExpression(BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt, bool evaluateLocally)
  553. {
  554. if (value->getOperator() == no_libraryinput)
  555. {
  556. IHqlExpression * seq = queryLibraryInputSequence(value);
  557. unsigned match = values.find(*seq);
  558. assertex(match != NotFound);
  559. tgt.setFromTranslated(&bound.item(match));
  560. }
  561. else
  562. translator.buildTempExpr(ctx, value, tgt);
  563. return RuntimeAlias;
  564. }
  565. void LibraryEvalContext::associateExpression(BuildCtx & ctx, IHqlExpression * value)
  566. {
  567. //Add the association by sequence number, because this is pre record normalization.
  568. assertex(value->getOperator() == no_libraryinput);
  569. IHqlExpression * seq = queryLibraryInputSequence(value);
  570. assertex(!values.contains(*seq));
  571. CHqlBoundTarget tempTarget;
  572. translator.createTempFor(ctx, value, tempTarget);
  573. values.append(*LINK(seq));
  574. CHqlBoundExpr tgt;
  575. tgt.setFromTarget(tempTarget);
  576. bound.append(*tgt.getTranslatedExpr());
  577. }
  578. void LibraryEvalContext::tempCompatiablityEnsureSerialized(const CHqlBoundTarget & tgt)
  579. {
  580. throwUnexpected();
  581. }