hqllib.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  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 "jhash.hpp"
  18. #include "jmisc.hpp"
  19. #include "jstream.ipp"
  20. #include "jdebug.hpp"
  21. #include "hql.hpp"
  22. #include "hqlattr.hpp"
  23. #include "hqlfold.hpp"
  24. #include "hqlthql.hpp"
  25. #include "hqltrans.ipp"
  26. #include "hqlutil.hpp"
  27. #include "hqlcpp.ipp"
  28. #include "hqlcatom.hpp"
  29. #include "hqlcpputil.hpp"
  30. #include "hqlgraph.ipp"
  31. #include "hqllib.ipp"
  32. #include "hqlwcpp.hpp"
  33. #include "hqlttcpp.ipp"
  34. #include "hqlinline.hpp"
  35. static IHqlExpression * queryLibraryInputSequence(IHqlExpression * expr)
  36. {
  37. IHqlExpression * arg = expr->queryChild(0);
  38. if (arg->isRecord())
  39. arg = expr->queryChild(1);
  40. return arg;
  41. }
  42. HqlCppLibrary::HqlCppLibrary(HqlCppTranslator & _translator, IHqlExpression * libraryInterface, ClusterType _clusterType) : translator(_translator), inputMapper(libraryInterface), clusterType(_clusterType)
  43. {
  44. assertex(libraryInterface->getOperator() == no_funcdef);
  45. scopeExpr = libraryInterface->queryChild(0);
  46. assertex(scopeExpr->getOperator() == no_virtualscope);
  47. streamedCount = 0;
  48. if (clusterType != HThorCluster)
  49. streamedCount = inputMapper.numStreamedInputs();
  50. extractOutputs();
  51. }
  52. void HqlCppLibrary::extractOutputs()
  53. {
  54. HqlExprArray symbols;
  55. scopeExpr->queryScope()->getSymbols(symbols);
  56. IHqlScope * scope = scopeExpr->queryScope();
  57. HqlDummyLookupContext dummyctx(NULL);
  58. ForEachItemIn(i, symbols)
  59. {
  60. IHqlExpression & cur = symbols.item(i);
  61. if (isExported(&cur))
  62. {
  63. _ATOM name = cur.queryName();
  64. OwnedHqlExpr value = scope->lookupSymbol(name, LSFpublic, dummyctx);
  65. if (value && !value->isFunction())
  66. {
  67. if (value->isDataset() || value->isDatarow() || value->queryType()->isScalar())
  68. {
  69. OwnedHqlExpr null = createNullExpr(value);
  70. outputs.append(*cur.cloneAllAnnotations(null));
  71. }
  72. }
  73. }
  74. }
  75. outputs.sort(compareSymbolsByName);
  76. }
  77. unsigned HqlCppLibrary::getInterfaceHash() const
  78. {
  79. unsigned crc = getHash(outputs, 0x12345678); // only hashes type and name, not implementation
  80. crc = getHash(inputMapper.queryRealParameters(), crc);
  81. if (translator.queryOptions().implicitLinkedChildRows)
  82. crc ^= 0x456271;
  83. if (crc == 0) crc = 0x87654321; // ensure it is non zero.
  84. return crc;
  85. }
  86. unsigned HqlCppLibrary::getHash(const HqlExprArray & values, unsigned crc) const
  87. {
  88. unsigned num = values.ordinality();
  89. crc = hashc((const byte *)&num, sizeof(num), crc);
  90. ForEachItemIn(i, values)
  91. {
  92. IHqlExpression & cur = values.item(i);
  93. //names are significant because inputs/outputs are ordered by name
  94. const char * name = cur.queryName()->str();
  95. crc = hashnc((const byte *)name, strlen(name), crc);
  96. ITypeInfo * type = cur.queryType();
  97. byte tc = type->getTypeCode();
  98. switch (tc)
  99. {
  100. case type_record:
  101. case type_row:
  102. case type_table:
  103. case type_groupedtable:
  104. case type_dictionary:
  105. {
  106. OwnedHqlExpr normalizedRecord = normalizeRecord(translator, cur.queryRecord());
  107. OwnedHqlExpr serialized = getSerializedForm(normalizedRecord, diskAtom);
  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. }