hqlstep.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jliball.hpp"
  14. #include "hql.hpp"
  15. #include "platform.h"
  16. #include "jlib.hpp"
  17. #include "jmisc.hpp"
  18. #include "jstream.ipp"
  19. #include "jdebug.hpp"
  20. #include "hql.hpp"
  21. #include "hqlthql.hpp"
  22. #include "hqlhtcpp.ipp"
  23. #include "hqlttcpp.ipp"
  24. #include "hqlutil.hpp"
  25. #include "hqlpmap.hpp"
  26. #include "hqlwcpp.hpp"
  27. #include "hqlcpputil.hpp"
  28. #include "hqltcppc.ipp"
  29. #include "hqlopt.hpp"
  30. #include "hqlfold.hpp"
  31. #include "hqlcerrors.hpp"
  32. #include "hqlcatom.hpp"
  33. #include "hqllib.ipp"
  34. #include "hqlresource.hpp"
  35. #include "hqlregex.ipp"
  36. #include "hqlsource.ipp"
  37. #include "hqlcse.ipp"
  38. #include "hqlgraph.ipp"
  39. #include "hqlscope.hpp"
  40. #include "hqlccommon.hpp"
  41. #include "hqlcppds.hpp"
  42. #include "eclhelper.hpp"
  43. #include "deffield.hpp"
  44. //===========================================================================
  45. class SteppingCondition
  46. {
  47. public:
  48. SteppingCondition(bool _onlyEquality, IHqlExpression * _left, IHqlExpression * _right, IHqlExpression * _rowsid);
  49. bool extractSteppingCondition(IHqlExpression * expr, IHqlExpression * sortOrder);
  50. IHqlExpression * createEqualitySortList();
  51. bool matchedAny() { return equalities.ordinality() != 0 || compareLhs; }
  52. IHqlExpression * queryRangeLeftSelector() { return compareLhs; }
  53. IHqlExpression * queryExtraFilter() { return extraCompare; }
  54. IHqlExpression * queryGlobalCompare() { return globalCompare; }
  55. IHqlExpression * getMaxLeftBeforeRight() { return getNegative(lhsDelta); }
  56. IHqlExpression * getMaxRightBeforeLeft() { return getNegative(rhsDelta); }
  57. protected:
  58. void clearRangeMatch()
  59. {
  60. compareLhs.clear();
  61. }
  62. bool containsRowsLeft(IHqlExpression * expr);
  63. bool extractCondition(IHqlExpression * expr, IHqlExpression * searchField);
  64. bool extractCondition(HqlExprArray & args, IHqlExpression * searchField);
  65. bool extractComparison(IHqlExpression * lhs, IHqlExpression * rhs, IHqlExpression * searchField, bool isEqual = false);
  66. bool isLeftRightInvariant(IHqlExpression * expr);
  67. IHqlExpression * simplifyArgument(IHqlExpression * expr, SharedHqlExpr & delta, bool invert);
  68. protected:
  69. HqlExprArray equalities;
  70. HqlExprAttr compareLhs;
  71. HqlExprAttr lhsDelta; // left.x >= right.x + lhsDelta
  72. HqlExprAttr rhsDelta; // right.x >= left.x + rhsDelta
  73. OwnedHqlExpr extraCompare;
  74. OwnedHqlExpr globalCompare;
  75. LinkedHqlExpr left;
  76. LinkedHqlExpr right;
  77. OwnedHqlExpr rowsLeftExpr;
  78. bool onlyEquality;
  79. bool explicitStepped;
  80. };
  81. SteppingCondition::SteppingCondition(bool _onlyEquality, IHqlExpression * _left, IHqlExpression * _right, IHqlExpression * _rowsid) : left(_left), right(_right), onlyEquality(_onlyEquality)
  82. {
  83. explicitStepped = false;
  84. rowsLeftExpr.setown(createDataset(no_rows, LINK(left), LINK(_rowsid)));
  85. }
  86. IHqlExpression * SteppingCondition::createEqualitySortList()
  87. {
  88. return createValueSafe(no_sortlist, makeSortListType(NULL), equalities);
  89. }
  90. bool SteppingCondition::extractSteppingCondition(IHqlExpression * expr, IHqlExpression * sortOrder)
  91. {
  92. HqlExprArray args, stepArgs;
  93. expr->unwindList(args, no_and);
  94. explicitStepped = false;;
  95. ForEachItemIn(i1, args)
  96. {
  97. IHqlExpression & cur = args.item(i1);
  98. if (cur.getOperator() == no_assertstepped)
  99. {
  100. explicitStepped = true;
  101. cur.queryChild(0)->unwindList(stepArgs, no_and);
  102. }
  103. }
  104. //The merge order defines the order that the stepping fields are processed in.
  105. HqlExprArray order, expandedOrder;
  106. unwindChildren(order, sortOrder);
  107. expandRowSelectors(expandedOrder, order);
  108. bool foundStepped = explicitStepped;
  109. ForEachItemIn(i2, expandedOrder)
  110. {
  111. IHqlExpression * cur = &expandedOrder.item(i2);
  112. if (explicitStepped)
  113. {
  114. if (!extractCondition(stepArgs, cur))
  115. {
  116. StringBuffer s;
  117. if (cur->getOperator() == no_select)
  118. s.append(cur->queryChild(1)->queryName());
  119. else
  120. getExprECL(cur, s);
  121. throwError1(HQLERR_SteppingNotMatchSortCondition, s.str());
  122. }
  123. if (stepArgs.ordinality() == 0)
  124. break;
  125. }
  126. else
  127. {
  128. if (!extractCondition(args, cur))
  129. break;
  130. foundStepped = true;
  131. }
  132. if (compareLhs)
  133. break;
  134. }
  135. if (stepArgs.ordinality())
  136. throwError1(HQLERR_SteppingNotMatchSortCondition, "");
  137. //Walk the list of non stepped condition, and retain any that are dependent on rows(left)
  138. ForEachItemIn(i3, args)
  139. {
  140. IHqlExpression & cur = args.item(i3);
  141. if (cur.getOperator() != no_assertstepped)
  142. {
  143. if (containsRowsLeft(&cur))
  144. extendConditionOwn(globalCompare, no_and, LINK(&cur));
  145. else
  146. extendConditionOwn(extraCompare, no_and, LINK(&cur));
  147. }
  148. }
  149. return foundStepped;
  150. }
  151. bool SteppingCondition::containsRowsLeft(IHqlExpression * expr)
  152. {
  153. OwnedHqlExpr null = createDataset(no_null, LINK(left->queryRecord()));
  154. OwnedHqlExpr replaceLeft = replaceExpression(expr, rowsLeftExpr, null);
  155. return replaceLeft != expr;
  156. }
  157. bool SteppingCondition::isLeftRightInvariant(IHqlExpression * expr)
  158. {
  159. //MORE: is his good enough?
  160. OwnedHqlExpr replaceLeft = replaceSelector(expr, left, right);
  161. OwnedHqlExpr replaceRight = replaceSelector(expr, right, left);
  162. if (expr == replaceLeft && expr == replaceRight)
  163. return true;
  164. return false;
  165. }
  166. void adjustValue(SharedHqlExpr & total, IHqlExpression * value, bool invert)
  167. {
  168. if (total)
  169. total.setown(adjustBoundIntegerValues(total, value, invert));
  170. else if (!invert)
  171. total.set(value);
  172. else
  173. total.setown(getNegative(value));
  174. }
  175. IHqlExpression * SteppingCondition::simplifyArgument(IHqlExpression * expr, SharedHqlExpr & delta, bool invert)
  176. {
  177. for (;;)
  178. {
  179. switch (expr->getOperator())
  180. {
  181. case no_cast:
  182. case no_implicitcast:
  183. if (!castPreservesInformationAndOrder(expr))
  184. return expr;
  185. expr = expr->queryChild(0);
  186. break;
  187. case no_add:
  188. {
  189. IHqlExpression * lhs = expr->queryChild(0);
  190. IHqlExpression * rhs = expr->queryChild(1);
  191. if (isLeftRightInvariant(rhs))
  192. {
  193. adjustValue(delta, rhs, invert);
  194. expr = lhs;
  195. }
  196. else if (isLeftRightInvariant(lhs))
  197. {
  198. adjustValue(delta, lhs, invert);
  199. expr = rhs;
  200. }
  201. else
  202. return expr;
  203. break;
  204. }
  205. case no_sub:
  206. {
  207. IHqlExpression * lhs = expr->queryChild(0);
  208. IHqlExpression * rhs = expr->queryChild(1);
  209. if (isLeftRightInvariant(rhs))
  210. {
  211. adjustValue(delta, rhs, !invert);
  212. expr = lhs;
  213. }
  214. else
  215. return expr;
  216. break;
  217. }
  218. default:
  219. return expr;
  220. }
  221. }
  222. }
  223. bool SteppingCondition::extractComparison(IHqlExpression * lhs, IHqlExpression * rhs, IHqlExpression * searchField, bool isEqual)
  224. {
  225. OwnedHqlExpr lhsSelect;
  226. OwnedHqlExpr delta;
  227. IHqlExpression * simpleLhs = simplifyArgument(lhs, delta, true);
  228. IHqlExpression * simpleRhs = simplifyArgument(rhs, delta, false);
  229. OwnedHqlExpr searchRightField = replaceSelector(searchField, left, right);
  230. if ((simpleLhs == searchField) && (simpleRhs == searchRightField))
  231. {
  232. compareLhs.set(searchField);
  233. if (!delta)
  234. delta.setown(getZero());
  235. if (lhsDelta)
  236. {
  237. StringBuffer s;
  238. throwError1(HQLERR_SteppedMultiRange, getExprECL(searchField,s).str());
  239. }
  240. lhsDelta.set(delta);
  241. if (isEqual)
  242. rhsDelta.setown(getNegative(delta));
  243. return true;
  244. }
  245. if ((simpleLhs == searchRightField) && (simpleRhs == searchField))
  246. {
  247. compareLhs.set(searchField);
  248. if (!delta)
  249. delta.setown(getZero());
  250. if (rhsDelta)
  251. {
  252. StringBuffer s;
  253. throwError1(HQLERR_SteppedMultiRange, getExprECL(searchRightField,s).str());
  254. }
  255. rhsDelta.set(delta);
  256. if (isEqual)
  257. lhsDelta.setown(getNegative(delta));
  258. return true;
  259. }
  260. return false;
  261. }
  262. bool SteppingCondition::extractCondition(IHqlExpression * expr, IHqlExpression * searchField)
  263. {
  264. //Search for LEFT.someSelect = right.someSelect
  265. node_operator op = expr->getOperator();
  266. assertex(op != no_and);
  267. if (op == no_eq)
  268. {
  269. IHqlExpression * lhs = expr->queryChild(0);
  270. IHqlExpression * rhs = expr->queryChild(1);
  271. if (lhs == searchField)
  272. {
  273. OwnedHqlExpr replaced = replaceSelector(rhs, right, left);
  274. if (replaced == lhs)
  275. {
  276. equalities.append(*LINK(lhs));
  277. return true;
  278. }
  279. }
  280. if (rhs == searchField)
  281. {
  282. OwnedHqlExpr replaced = replaceSelector(lhs, right, left);
  283. if (replaced == rhs)
  284. {
  285. equalities.append(*LINK(rhs));
  286. return true;
  287. }
  288. }
  289. }
  290. if (!onlyEquality)
  291. {
  292. //left.x + d1 >= right.wpos + d2 (d1, d2 may be subtracted, and may be implicit casts in the expression)
  293. //normalize to left.x >= right.x + delta
  294. //left => maxRightAfterLeft = -delta; right => maxRightBeforeLeft = -delta;
  295. switch (op)
  296. {
  297. case no_ge:
  298. return extractComparison(expr->queryChild(0), expr->queryChild(1), searchField);
  299. case no_le:
  300. return extractComparison(expr->queryChild(1), expr->queryChild(0), searchField);
  301. case no_between:
  302. if (extractComparison(expr->queryChild(0), expr->queryChild(1), searchField))
  303. {
  304. if (extractComparison(expr->queryChild(2), expr->queryChild(0), searchField))
  305. return true;
  306. clearRangeMatch();
  307. }
  308. break;
  309. case no_eq:
  310. return extractComparison(expr->queryChild(0), expr->queryChild(1), searchField, true);
  311. }
  312. }
  313. return false;
  314. }
  315. bool SteppingCondition::extractCondition(HqlExprArray & args, IHqlExpression * searchField)
  316. {
  317. assertex(!compareLhs);
  318. UnsignedArray matched;
  319. ForEachItemIn(i, args)
  320. {
  321. IHqlExpression & cur = args.item(i);
  322. if (extractCondition(&cur, searchField))
  323. matched.append(i);
  324. }
  325. if (compareLhs)
  326. {
  327. //Only matched in one direction
  328. if (!lhsDelta || !rhsDelta)
  329. {
  330. if (explicitStepped)
  331. throwError(HQLERR_SteppedRangeOnlyOneDirection);
  332. matched.kill();
  333. }
  334. else
  335. {
  336. ForEachItemInRev(i2, matched)
  337. {
  338. IHqlExpression & cur = args.item(matched.item(i2));
  339. extendConditionOwn(extraCompare, no_and, LINK(&cur));
  340. }
  341. }
  342. }
  343. ForEachItemInRev(i2, matched)
  344. args.remove(matched.item(i2));
  345. return matched.ordinality() != 0;
  346. }
  347. //---------------------------------------------------------------------------
  348. void SteppingFieldSelection::expandTransform(IHqlExpression * expr)
  349. {
  350. IHqlExpression * parent = expr->queryChild(0)->queryNormalizedSelector();
  351. TableProjectMapper mapper(expr);
  352. if (!mapper.isMappingKnown())
  353. throwError(HQLERR_CantProjectStepping);
  354. fields.setown(mapper.expandFields(fields, ds, parent));
  355. fields.setown(expandCreateRowSelectors(fields));
  356. ds.set(parent);
  357. }
  358. void SteppingFieldSelection::extractFields(SteppingFieldSelection & steppingFields)
  359. {
  360. steppingFields.ds.set(ds);
  361. HqlExprArray args;
  362. ForEachChild(i, fields)
  363. {
  364. IHqlExpression * cur = fields->queryChild(i);
  365. args.append(*extractSelect(cur));
  366. }
  367. steppingFields.fields.setown(fields->clone(args));
  368. }
  369. static void throwTooComplexToStep(IHqlExpression * expr)
  370. {
  371. StringBuffer ecl;
  372. getExprECL(expr, ecl, true, false);
  373. throwError1(HQLERR_TooComplexToStep, ecl.str());
  374. }
  375. IHqlExpression * SteppingFieldSelection::extractSelect(IHqlExpression * expr)
  376. {
  377. for (;;)
  378. {
  379. switch (expr->getOperator())
  380. {
  381. case no_filepos:
  382. case no_file_logicalname:
  383. //MORE: We should really catch more problems like this...
  384. throwError(HQLERR_NoSteppingOnPayload);
  385. case no_cast:
  386. case no_implicitcast:
  387. {
  388. if (!castPreservesValueAndOrder(expr))
  389. {
  390. switch (expr->queryChild(0)->getOperator())
  391. {
  392. case no_filepos:
  393. case no_file_logicalname:
  394. throwError(HQLERR_NoSteppingOnPayload);
  395. default:
  396. throwTooComplexToStep(expr);
  397. }
  398. }
  399. expr = expr->queryChild(0);
  400. break;
  401. }
  402. case no_add:
  403. case no_sub:
  404. {
  405. //cope with biasing on indexes.
  406. IHqlExpression * rhs = expr->queryChild(1);
  407. switch (rhs->getOperator())
  408. {
  409. case no_constant:
  410. break;
  411. default:
  412. throwTooComplexToStep(expr);
  413. }
  414. expr = expr->queryChild(0);
  415. break;
  416. }
  417. case no_select:
  418. return LINK(expr);
  419. default:
  420. throwTooComplexToStep(expr);
  421. }
  422. }
  423. }
  424. void SteppingFieldSelection::gatherFieldOffsetSizes(HqlCppTranslator & translator, UnsignedArray & result)
  425. {
  426. //A pseudo context in somewhere that will never be generated.
  427. BuildCtx ctx(*translator.queryCode(), _internal_Atom);
  428. ctx.addGroup();
  429. translator.bindTableCursor(ctx, ds, "x");
  430. CHqlBoundExpr bound;
  431. StringBuffer s;
  432. ForEachChild(i, fields)
  433. {
  434. IHqlExpression * cur = fields->queryChild(i);
  435. assertex(cur->getOperator() == no_select);
  436. Owned<IReferenceSelector> selector = translator.buildActiveReference(ctx, cur);
  437. selector->getOffset(ctx, bound);
  438. IValue * offsetValue = bound.expr->queryValue();
  439. if (offsetValue)
  440. result.append((unsigned)offsetValue->getIntValue());
  441. else
  442. throwError1(HQLERR_SteppedVariableOffset, getExprECL(cur, s).str());
  443. selector->getSize(ctx, bound);
  444. IValue * sizeValue = bound.expr->queryValue();
  445. if (sizeValue)
  446. result.append((unsigned)sizeValue->getIntValue());
  447. else
  448. throwError1(HQLERR_SteppedVariableSize, getExprECL(cur, s).str());
  449. }
  450. }
  451. IHqlExpression * SteppingFieldSelection::generateSteppingMeta(HqlCppTranslator & translator)
  452. {
  453. OwnedHqlExpr normalFields = replaceSelector(fields, ds, queryActiveTableSelector());
  454. OwnedHqlExpr key = createAttribute(_steppedMeta_Atom, LINK(ds->queryRecord()->queryBody()), LINK(normalFields));
  455. BuildCtx declarectx(*translator.queryCode(), declareAtom);
  456. HqlExprAssociation * match = declarectx.queryMatchExpr(key);
  457. if (match)
  458. return match->queryExpr();
  459. BuildCtx classctx(declarectx);
  460. StringBuffer s, s2;
  461. StringBuffer memberName, offsetName;
  462. unique_id_t id = translator.getUniqueId();
  463. appendUniqueId(memberName.append("st"), id);
  464. appendUniqueId(offsetName.append("so"), id);
  465. UnsignedArray offsets;
  466. gatherFieldOffsetSizes(translator, offsets);
  467. unsigned lenOffsets = offsets.ordinality();
  468. s.clear();
  469. s.append("CFieldOffsetSize ").append(offsetName).append("[").append(lenOffsets/2).append("] = {");
  470. for (unsigned i=0; i < lenOffsets; i += 2)
  471. {
  472. if (i) s.append(",");
  473. s.append("{").append(offsets.item(i)).append(",").append(offsets.item(i+1)).append("}");
  474. }
  475. s.append("};");
  476. declarectx.setNextPriority(SteppedPrio);
  477. declarectx.addQuoted(s);
  478. //MORE: This might be better commoned up globally, depending of number of instances
  479. classctx.setNextPriority(SteppedPrio);
  480. classctx.addQuotedCompound(s.clear().append("struct C").append(memberName).append(" : public ISteppingMeta"), s2.append(" ").append(memberName).append(";").str());
  481. translator.doBuildUnsignedFunction(classctx, "getNumFields", lenOffsets/2);
  482. classctx.addQuoted(s.clear().append("virtual const CFieldOffsetSize * queryFields() override { return ").append(offsetName).append("; }"));
  483. //compare function.
  484. {
  485. StringBuffer compareName;
  486. translator.getUniqueId(compareName.append("c"));
  487. OwnedITypeInfo intType = makeIntType(4, true);
  488. OwnedHqlExpr result = createVariable("ret", LINK(intType));
  489. BuildCtx comparectx(classctx);
  490. comparectx.addQuotedCompoundLiteral("class Compare : public IRangeCompare", s2.clear().append(" ").append(compareName).append(";"));
  491. translator.doBuildUnsignedFunction(comparectx, "maxFields", lenOffsets/2);
  492. {
  493. MemberFunction func(translator, comparectx, "virtual int docompare(const void * _left,const void * _right, unsigned numFields) const override");
  494. func.ctx.addQuotedLiteral("const byte * left = (const byte *)_left;");
  495. func.ctx.addQuotedLiteral("const byte * right = (const byte *)_right;");
  496. func.ctx.addQuotedLiteral("int ret;");
  497. func.ctx.addQuoted(s.clear().append("if (numFields < 1) return 0;"));
  498. OwnedHqlExpr selSeq = createDummySelectorSequence();
  499. BoundRow * left = translator.bindTableCursor(func.ctx, ds, "left", no_left, selSeq);
  500. BoundRow * right = translator.bindTableCursor(func.ctx, ds, "right", no_right, selSeq);
  501. ForEachChild(i, fields)
  502. {
  503. IHqlExpression * cur = fields->queryChild(i);
  504. if (i)
  505. func.ctx.addQuoted(s.clear().append("if (ret || (numFields < ").append(i+1).append(")) return ret;"));
  506. OwnedHqlExpr lhs = replaceSelector(cur, ds, left->querySelector());
  507. OwnedHqlExpr rhs = replaceSelector(cur, ds, right->querySelector());
  508. OwnedHqlExpr order = createValue(no_order, makeIntType(4, true), LINK(lhs), LINK(rhs));
  509. translator.buildAssignToTemp(func.ctx, result, order);
  510. }
  511. func.ctx.addReturn(result);
  512. }
  513. classctx.addQuoted(s.clear().append("virtual IRangeCompare * queryCompare() override { return &").append(compareName).append("; }"));
  514. }
  515. //distance function - very similar to compare
  516. {
  517. StringBuffer distanceName;
  518. translator.getUniqueId(distanceName.append("c"));
  519. OwnedITypeInfo intType = makeIntType(4, true);
  520. OwnedHqlExpr result = createVariable("ret", LINK(intType));
  521. BuildCtx distancectx(classctx);
  522. distancectx.addQuotedCompoundLiteral("class Distance : public IDistanceCalculator", s2.clear().append(" ").append(distanceName).append(";"));
  523. {
  524. MemberFunction func(translator, distancectx, "virtual unsigned getDistance(unsigned __int64 & distance, const void * _before, const void * _after, unsigned numFields) const override");
  525. func.ctx.addQuotedLiteral("const byte * before = (const byte *)_before;");
  526. func.ctx.addQuotedLiteral("const byte * after = (const byte *)_after;");
  527. OwnedHqlExpr selSeq = createDummySelectorSequence();
  528. OwnedITypeInfo distanceType = makeIntType(8, false);
  529. OwnedHqlExpr distanceExpr = createVariable("distance", LINK(distanceType));
  530. BoundRow * left = translator.bindTableCursor(func.ctx, ds, "before", no_left, selSeq);
  531. BoundRow * right = translator.bindTableCursor(func.ctx, ds, "after", no_right, selSeq);
  532. ForEachChild(i, fields)
  533. {
  534. IHqlExpression * cur = fields->queryChild(i);
  535. func.ctx.addQuoted(s.clear().append("if (numFields < ").append(i+1).append(") return DISTANCE_EXACT_MATCH;"));
  536. OwnedHqlExpr lhs = replaceSelector(cur, ds, left->querySelector());
  537. OwnedHqlExpr rhs = replaceSelector(cur, ds, right->querySelector());
  538. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(lhs), LINK(rhs));
  539. BuildCtx subctx(func.ctx);
  540. translator.buildFilter(subctx, compare);
  541. OwnedHqlExpr value;
  542. if (lhs->queryType()->isInteger())
  543. value.setown(createValue(no_sub, LINK(distanceType), ensureExprType(rhs, distanceType), ensureExprType(lhs, distanceType)));
  544. else
  545. value.setown(getSizetConstant(1));
  546. translator.buildAssignToTemp(subctx, distanceExpr, value);
  547. subctx.addQuotedF("return %u;", i+1);
  548. }
  549. func.ctx.addQuotedLiteral("return DISTANCE_EXACT_MATCH;");
  550. }
  551. classctx.addQuoted(s.clear().append("virtual IDistanceCalculator * queryDistance() override { return &").append(distanceName).append("; }"));
  552. }
  553. StringBuffer resultText;
  554. if (translator.queryOptions().spanMultipleCpp)
  555. {
  556. translator.createAccessFunctions(resultText, declarectx, SteppedPrio, "ISteppingMeta", memberName);
  557. resultText.append("()");
  558. }
  559. else
  560. resultText.append(memberName);
  561. OwnedHqlExpr func = createVariable(resultText.str(), makeVoidType());
  562. declarectx.associateExpr(key, func);
  563. return func;
  564. }
  565. void SteppingFieldSelection::generateSteppingMetaMember(HqlCppTranslator & translator, BuildCtx & ctx, const char * name)
  566. {
  567. IHqlExpression * func = generateSteppingMeta(translator);
  568. StringBuffer s;
  569. s.clear().append("virtual ISteppingMeta * query").append(name).append("() override { return & ");
  570. translator.generateExprCpp(s, func);
  571. s.append(";}");
  572. ctx.addQuoted(s);
  573. }
  574. IHqlExpression * SteppingFieldSelection::invertTransform(IHqlExpression * expr, IHqlExpression * select)
  575. {
  576. LinkedHqlExpr result = select;
  577. for (;;)
  578. {
  579. node_operator op = expr->getOperator();
  580. switch (op)
  581. {
  582. case no_cast:
  583. case no_implicitcast:
  584. {
  585. IHqlExpression * uncast = expr->queryChild(0);
  586. result.setown(ensureExprType(result, uncast->queryType()));
  587. expr = uncast;
  588. break;
  589. }
  590. case no_add:
  591. case no_sub:
  592. {
  593. node_operator newOp = (op == no_add) ? no_sub : no_add;
  594. IHqlExpression * rhs = expr->queryChild(1);
  595. result.setown(createValue(newOp, expr->getType(), LINK(result), LINK(rhs)));
  596. expr = expr->queryChild(0);
  597. break;
  598. }
  599. case no_select:
  600. return result.getLink();
  601. default:
  602. throwUnexpectedOp(op);
  603. }
  604. }
  605. }
  606. void SteppingFieldSelection::set(IHqlExpression * _ds, IHqlExpression * _fields)
  607. {
  608. ds.set(_ds);
  609. fields.set(_fields);
  610. }
  611. void SteppingFieldSelection::setStepping(IHqlExpression * expr)
  612. {
  613. ds.set(expr->queryNormalizedSelector());
  614. fields.set(expr->queryChild(1));
  615. }
  616. //---------------------------------------------------------------------------
  617. bool HqlCppTranslator::buildNWayInputs(CIArrayOf<ABoundActivity> & inputs, BuildCtx & ctx, IHqlExpression * input)
  618. {
  619. if (input->getOperator() == no_datasetlist)
  620. {
  621. IHqlExpression * record = input->queryChild(0);
  622. ForEachChild(i, input)
  623. {
  624. IHqlExpression * cur = input->queryChild(i);
  625. if (!recordTypesMatch(cur->queryRecord(), record))
  626. throwError(HQLERR_InconsistentNaryInput);
  627. inputs.append(*buildCachedActivity(ctx, cur));
  628. }
  629. return false;
  630. }
  631. inputs.append(*buildCachedActivity(ctx, input));
  632. return true;
  633. }
  634. ABoundActivity * HqlCppTranslator::doBuildActivityRowsetRange(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * rowset, IHqlExpression * inputSelection)
  635. {
  636. bool isNWayInput;
  637. ThorActivityKind kind;
  638. const char * argName;
  639. CIArrayOf<ABoundActivity> inputs;
  640. IHqlExpression * graphId = NULL;
  641. switch (rowset->getOperator())
  642. {
  643. case no_getgraphloopresultset:
  644. {
  645. kind = TAKnwaygraphloopresultread;
  646. argName = "NWayGraphLoopResultRead";
  647. isNWayInput = true;
  648. graphId = rowset->queryChild(1);
  649. break;
  650. }
  651. case no_datasetlist:
  652. {
  653. kind = TAKnwayinput;
  654. argName = "NWayInput";
  655. isNWayInput = false;
  656. ForEachChild(i, rowset)
  657. inputs.append(*buildCachedActivity(ctx, rowset->queryChild(i)));
  658. break;
  659. }
  660. default:
  661. throwError(HQLERR_UnsupportedRowsetRangeParam);
  662. return nullptr; // Cannot reach here, but previous throw is virtual, so the compiler cannot be sure it does not return
  663. }
  664. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, argName);
  665. buildActivityFramework(instance);
  666. buildInstancePrefix(instance);
  667. OwnedITypeInfo castType = makeSetType(LINK(unsignedType));
  668. OwnedHqlExpr castList = ensureExprType(inputSelection, castType);
  669. OwnedHqlExpr normalized = normalizeListCasts(castList);
  670. {
  671. MemberFunction func(*this, instance->startctx, "virtual void getInputSelection(bool & __isAllResult, size32_t & __lenResult, void * & __result) override");
  672. doBuildFunctionReturn(func.ctx, castType, normalized);
  673. }
  674. if ((kind == TAKnwaygraphloopresultread) && isGrouped(rowset))
  675. doBuildBoolFunction(instance->classctx, "grouped", true);
  676. if (graphId && targetRoxie())
  677. addGraphIdAttribute(instance, ctx, graphId);
  678. buildInstanceSuffix(instance);
  679. ForEachItemIn(idx2, inputs)
  680. buildConnectInputOutput(ctx, instance, &inputs.item(idx2), 0, idx2, NULL, isNWayInput);
  681. return instance->getBoundActivity();
  682. }
  683. ABoundActivity * HqlCppTranslator::doBuildActivityRowsetRange(BuildCtx & ctx, IHqlExpression * expr)
  684. {
  685. IHqlExpression * ds = expr->queryChild(0);
  686. IHqlExpression * inputSelection = expr->queryChild(1);
  687. return doBuildActivityRowsetRange(ctx, expr, ds, inputSelection);
  688. }
  689. ABoundActivity * HqlCppTranslator::doBuildActivityRowsetIndex(BuildCtx & ctx, IHqlExpression * expr)
  690. {
  691. IHqlExpression * dataset = expr->queryChild(0);
  692. if (dataset->getOperator() == no_getgraphloopresultset)
  693. {
  694. throwUnexpected(); // this should have been translated elsewhere...
  695. OwnedHqlExpr newExpr = createDataset(no_getgraphloopresult, LINK(dataset->queryRecord()), createComma(LINK(dataset->queryChild(1)), LINK(expr->queryChild(1))));
  696. return buildActivity(ctx, newExpr, false);
  697. }
  698. CIArrayOf<ABoundActivity> inputs;
  699. bool isNWayInput = buildNWayInputs(inputs, ctx, dataset);
  700. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnwayselect, expr, "NWaySelect");
  701. buildActivityFramework(instance);
  702. buildInstancePrefix(instance);
  703. doBuildUnsignedFunction(instance->startctx, "getInputIndex", expr->queryChild(1));
  704. buildInstanceSuffix(instance);
  705. ForEachItemIn(idx2, inputs)
  706. buildConnectInputOutput(ctx, instance, &inputs.item(idx2), 0, idx2, NULL, isNWayInput);
  707. return instance->getBoundActivity();
  708. }
  709. ABoundActivity * HqlCppTranslator::doBuildActivityNWayMerge(BuildCtx & ctx, IHqlExpression * expr)
  710. {
  711. IHqlExpression * dataset = expr->queryChild(0);
  712. CIArrayOf<ABoundActivity> inputs;
  713. bool isNWayInput = buildNWayInputs(inputs, ctx, dataset);
  714. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnwaymerge, expr, "NWayMerge");
  715. buildActivityFramework(instance);
  716. buildInstancePrefix(instance);
  717. IHqlExpression * sortOrder = expr->queryChild(1);
  718. //NOTE: left is used instead of dataset in sort list
  719. DatasetReference dsRef(dataset, no_left, querySelSeq(expr));
  720. buildCompareFuncHelper(*this, *instance, "compare", sortOrder, dsRef);
  721. if (expr->hasAttribute(dedupAtom))
  722. doBuildBoolFunction(instance->classctx, "dedup", true);
  723. SteppingFieldSelection stepping;
  724. IHqlExpression * left = dsRef.querySelector();
  725. stepping.set(left, sortOrder);
  726. stepping.generateSteppingMetaMember(*this, instance->classctx, "SteppingMeta");
  727. buildInstanceSuffix(instance);
  728. ForEachItemIn(idx2, inputs)
  729. buildConnectInputOutput(ctx, instance, &inputs.item(idx2), 0, idx2, NULL, isNWayInput);
  730. return instance->getBoundActivity();
  731. }
  732. ABoundActivity * HqlCppTranslator::doBuildActivityNWayMergeJoin(BuildCtx & ctx, IHqlExpression * expr)
  733. {
  734. node_operator op = expr->getOperator();
  735. if (targetThor() && !isLocalActivity(expr) && !isGroupedActivity(expr) && !insideChildQuery(ctx))
  736. {
  737. //Should default to an error in a later version, but LOCAL wasn't allowed on MERGEJOIN so make a warning for now.
  738. reportWarning(CategoryUnexpected, SeverityUnknown, NULL, ECODETEXT(HQLWRN_OnlyLocalMergeJoin), getOpString(op));
  739. OwnedHqlExpr localExpr = appendLocalAttribute(expr);
  740. return doBuildActivityNWayMergeJoin(ctx, localExpr);
  741. }
  742. IHqlExpression * dataset = expr->queryChild(0);
  743. CIArrayOf<ABoundActivity> inputs;
  744. bool isNWayInput = buildNWayInputs(inputs, ctx, dataset);
  745. ThorActivityKind kind = (op == no_mergejoin) ? TAKnwaymergejoin : TAKnwayjoin;
  746. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "NWayMergeJoin");
  747. buildActivityFramework(instance);
  748. buildInstancePrefix(instance);
  749. IHqlExpression * mofn = expr->queryAttribute(mofnAtom);
  750. bool leftonly = expr->hasAttribute(leftonlyAtom);
  751. bool leftouter = expr->hasAttribute(leftouterAtom);
  752. IHqlExpression * selSeq = querySelSeq(expr);
  753. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  754. IHqlExpression * transform = (op == no_nwayjoin) ? expr->queryChild(2) : NULL;
  755. IHqlExpression * sortOrder = (op == no_nwayjoin) ? expr->queryChild(3) : expr->queryChild(2);
  756. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  757. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  758. SteppingCondition stepCondition(false, left, right, rowsid);
  759. stepCondition.extractSteppingCondition(expr->queryChild(1), sortOrder);
  760. if (!stepCondition.matchedAny())
  761. throwError(HQLERR_JoinNotMatchSortCondition);
  762. OwnedHqlExpr equalityList = stepCondition.createEqualitySortList();
  763. IHqlExpression * rangeSelect = stepCondition.queryRangeLeftSelector();
  764. IHqlExpression * internalFlags = queryAttributeChild(expr, internalFlagsAtom, 0);
  765. IHqlExpression * skew = expr->queryAttribute(skewAtom);
  766. //Now generate all the helper functions....
  767. bool createClearRow = true;//(!leftouter && !leftonly);
  768. StringBuffer flags;
  769. flags.append("|MJFhasdistance");
  770. if (leftouter)
  771. flags.append("|MJFleftouter");
  772. else if (leftonly)
  773. flags.append("|MJFleftonly");
  774. else if (mofn)
  775. flags.append("|MJFmofn");
  776. else
  777. flags.append("|MJFinner");
  778. if (expr->hasAttribute(dedupAtom)) flags.append("|MJFdedup");
  779. if (expr->hasAttribute(steppedAtom)) flags.append("|MJFstepped");
  780. if (transform) flags.append("|MJFtransform");
  781. if (rangeSelect) flags.append("|MJFhasrange");
  782. if (expr->hasAttribute(assertAtom) && generateAsserts()) flags.append("|MJFassertsorted");
  783. if (stepCondition.queryGlobalCompare()) flags.append("|MJFglobalcompare");
  784. if (createClearRow) flags.append("|MJFhasclearlow");
  785. if (skew) flags.append("|MJFhaspartition");
  786. if (internalFlags) flags.append("|").append(getIntValue(internalFlags, 0));
  787. if (flags.length())
  788. doBuildUnsignedFunction(instance->classctx, "getJoinFlags", flags.str()+1);
  789. //NOTE: left is used instead of dataset in sort list
  790. DatasetReference leftRef(dataset, no_left, querySelSeq(expr));
  791. unsigned numEqualFields = equalityList->numChildren();
  792. doBuildUnsignedFunction(instance->classctx, "numEqualFields", numEqualFields);
  793. doBuildUnsignedFunction(instance->classctx, "numOrderFields", sortOrder->numChildren());
  794. //virtual ICompare * queryEqualCompare()
  795. buildCompareFuncHelper(*this, *instance, "equalCompare", equalityList, leftRef);
  796. //virtual ICompareEq * queryExactCompare()
  797. {
  798. buildCompareEqMember(instance->classctx, "EqualCompareEq", equalityList, leftRef);
  799. }
  800. //virtual ICompareEq * queryPartitionCompareEq()
  801. if (skew)
  802. {
  803. HqlExprArray skewArgs;
  804. unwindChildren(skewArgs, skew);
  805. OwnedHqlExpr skewOrder = createSortList(skewArgs);
  806. DatasetReference datasetRef(dataset);
  807. buildCompareEqMember(instance->classctx, "PartitionCompareEq", skewOrder, leftRef);
  808. }
  809. //virtual ISteppingMeta * querySteppingMeta()
  810. {
  811. SteppingFieldSelection stepping;
  812. stepping.set(left, sortOrder);
  813. stepping.generateSteppingMetaMember(*this, instance->classctx, "SteppingMeta");
  814. }
  815. //virtual IOutputMetaData * queryInputMeta()
  816. {
  817. MetaInstance inputmeta(*this, dataset->queryRecord(), isGrouped(dataset));
  818. buildMetaInfo(inputmeta);
  819. StringBuffer s;
  820. s.append("virtual IOutputMetaData * queryInputMeta() override { return &").append(inputmeta.queryInstanceObject()).append("; }");
  821. instance->classctx.addQuoted(s);
  822. }
  823. //NOTE: left is used instead of dataset in sort list
  824. //virtual ICompare * queryMergeCompare()
  825. buildCompareFuncHelper(*this, *instance, "mergeCompare", sortOrder, leftRef);
  826. if (createClearRow)
  827. {
  828. BuildCtx funcctx(instance->startctx);
  829. OwnedHqlExpr func = getClearRecordFunction(dataset->queryRecord(), -1);
  830. StringBuffer s;
  831. generateExprCpp(s.append("virtual size32_t createLowInputRow(ARowBuilder & crSelf) override { return "), func).append("(crSelf, ctx); }");
  832. funcctx.addQuoted(s);
  833. }
  834. if (rangeSelect)
  835. {
  836. OwnedITypeInfo rangeType = makeIntType(8, false);
  837. OwnedITypeInfo distanceType = makeIntType(8, true);
  838. OwnedHqlExpr rangeValue = ensureExprType(rangeSelect, rangeType);
  839. OwnedHqlExpr bias;
  840. if (rangeSelect->queryType()->isSigned())
  841. {
  842. bias.setown(getHozedBias(rangeSelect->queryType()));
  843. rangeValue.setown(createValue(no_add, rangeValue->getType(), LINK(rangeValue), ensureExprType(bias, rangeType)));
  844. }
  845. if (sortOrder->numChildren() != numEqualFields + 1)
  846. throwError(HQLERR_SortOrderMustMatchJoinFields);
  847. //virtual unsigned __int64 extractRangeValue(const void * input); // distance is assumed to be unsigned, code generator must bias if not true.
  848. {
  849. MemberFunction func(*this, instance->startctx, "virtual unsigned __int64 extractRangeValue(const void * _left) override");
  850. func.ctx.addQuotedLiteral("const byte * left = (const byte *)_left;");
  851. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  852. buildReturn(func.ctx, rangeValue);
  853. }
  854. //virtual void adjustRangeValue(void * self, const void * input, __int64 delta); // implementation must ensure field doesn't go -ve.
  855. {
  856. MemberFunction func(*this, instance->startctx, "virtual void adjustRangeValue(ARowBuilder & crSelf, const void * _left, __int64 delta) override");
  857. ensureRowAllocated(func.ctx, "crSelf");
  858. func.ctx.addQuotedLiteral("const byte * left = (const byte *)_left;");
  859. BoundRow * self = bindSelf(func.ctx, dataset, "crSelf");
  860. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  861. ForEachChild(i, equalityList)
  862. {
  863. IHqlExpression * cur = equalityList->queryChild(i);
  864. OwnedHqlExpr target = replaceSelector(cur, left, self->querySelector());
  865. buildAssign(func.ctx, target, cur);
  866. }
  867. OwnedHqlExpr target = replaceSelector(rangeSelect, left, self->querySelector());
  868. OwnedHqlExpr delta = createVariable("delta", LINK(distanceType));
  869. OwnedHqlExpr castDelta = ensureExprType(delta, rangeType);
  870. OwnedHqlExpr minusDelta = getNegative(delta);
  871. OwnedHqlExpr cond = createBoolExpr(no_or,
  872. createBoolExpr(no_ge, LINK(delta), ensureExprType(queryZero(), distanceType)),
  873. createBoolExpr(no_ge, LINK(rangeValue), ensureExprType(minusDelta, rangeType)));
  874. OwnedHqlExpr firstValue = bias ? getNegative(bias) : getZero();
  875. OwnedHqlExpr assignValue = createValue(no_if, rangeSelect->getType(),
  876. LINK(cond),
  877. createValue(no_add, rangeSelect->getType(), LINK(rangeSelect), ensureExprType(delta, rangeSelect->queryType())),
  878. ensureExprType(firstValue, rangeSelect->queryType()));
  879. buildAssign(func.ctx, target, assignValue);
  880. }
  881. //virtual __int64 maxRightBeforeLeft()
  882. {
  883. MemberFunction func(*this, instance->startctx, "virtual __int64 maxRightBeforeLeft() override");
  884. OwnedHqlExpr mrbl = stepCondition.getMaxRightBeforeLeft();
  885. buildReturn(func.ctx, mrbl);
  886. }
  887. //virtual __int64 maxLeftBeforeRight()
  888. {
  889. MemberFunction func(*this, instance->startctx, "virtual __int64 maxLeftBeforeRight() override");
  890. OwnedHqlExpr mlbr = stepCondition.getMaxLeftBeforeRight();
  891. buildReturn(func.ctx, mlbr);
  892. }
  893. }
  894. //virtual ICompareEq * queryNonSteppedCompare()
  895. IHqlExpression * compare = stepCondition.queryExtraFilter();
  896. if (compare)
  897. buildCompareEqMemberLR(instance->nestedctx, "NonSteppedCompare", compare, dataset, dataset, selSeq);
  898. //virtual INaryCompareEq * queryGlobalCompare() = 0;
  899. IHqlExpression * globalCompare = stepCondition.queryGlobalCompare();
  900. if (globalCompare)
  901. buildNaryCompareMember(instance->startctx, "GlobalCompare", globalCompare, dataset, selSeq, rowsid);
  902. //virtual size32_t transform(ARowBuilder & crSelf, unsigned _num, const void * * _rows)
  903. if (transform)
  904. {
  905. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, unsigned numRows, const void * * _rows) override");
  906. ensureRowAllocated(func.ctx, "crSelf");
  907. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _rows[0];");
  908. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _rows[1];");
  909. func.ctx.addQuotedLiteral("const byte * * rows = (const byte * *) _rows;");
  910. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  911. bindTableCursor(func.ctx, dataset, "right", no_right, selSeq);
  912. bindRows(func.ctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  913. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  914. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  915. doTransform(func.ctx, transform, selfCursor);
  916. buildReturnRecordSize(func.ctx, selfCursor);
  917. }
  918. if (mofn)
  919. {
  920. doBuildUnsignedFunction(instance->startctx, "getMinMatches", mofn->queryChild(0));
  921. if (queryRealChild(mofn, 1))
  922. doBuildUnsignedFunction(instance->startctx, "getMaxMatches", mofn->queryChild(1));
  923. }
  924. if (leftonly)
  925. {
  926. //Create a function to apply a delta to the last field, it assumes that overflow isn't going to be a problem.
  927. IHqlExpression * lastJoinField = equalityList->queryChild(numEqualFields-1);
  928. if (lastJoinField->queryType()->isInteger())
  929. {
  930. MemberFunction func(*this, instance->startctx, "virtual bool createNextJoinValue(ARowBuilder & crSelf, const void * _value) override");
  931. ensureRowAllocated(func.ctx, "crSelf");
  932. func.ctx.addQuotedLiteral("const byte * value = (const byte *)_value;");
  933. BoundRow * self = bindSelf(func.ctx, dataset, "crSelf");
  934. bindTableCursor(func.ctx, dataset, "value", no_left, selSeq);
  935. ForEachChild(i, equalityList)
  936. {
  937. IHqlExpression * cur = equalityList->queryChild(i);
  938. OwnedHqlExpr target = replaceSelector(cur, left, self->querySelector());
  939. LinkedHqlExpr source = cur;
  940. if (i == numEqualFields-1)
  941. source.setown(adjustValue(cur, 1));
  942. buildAssign(func.ctx, target, source);
  943. }
  944. buildReturn(func.ctx, queryBoolExpr(true));
  945. }
  946. }
  947. buildInstanceSuffix(instance);
  948. ForEachItemIn(idx2, inputs)
  949. buildConnectInputOutput(ctx, instance, &inputs.item(idx2), 0, idx2, NULL, isNWayInput);
  950. return instance->getBoundActivity();
  951. }
  952. //---------------------------------------------------------------------------
  953. /*
  954. Stepping info.
  955. Assume we have
  956. a) an index read, stepped on [doc, wpos, wip]
  957. b) an index read, stepped on [doc, wpos]
  958. c) an index read, stepped on [doc, wpos, wip]
  959. d) mergejoin(a,b, merge[doc, wpos, wip], left.doc = right.doc));
  960. e) join(d, c, stepped(left.doc = right.doc, right.wpos in range left.wpos - 5, left.wpos + 10), sorted([doc, wpos, wip]);
  961. f) SORT(e, [doc, wpos, wip], RANGE(left.wpos - right.wpos between [-5, 5]))
  962. // could push top and right scope for range, but not very nice..., introduce a new no_sort keyword regardless of syntax.
  963. We have
  964. a) static stepping = [doc,wpos,wip], dynamic matchee
  965. b) static stepping = [doc, wpos], dyamic matches
  966. c) same as a
  967. d) static stepping = [doc, wpos, wip]
  968. dynamic = dynamic for input#0 intersected with own static stepping.
  969. because a merge, all fields used in the merge can be stepped.
  970. e) static = [doc, wpos], because those are the conditions used in the join condition, and each of those values is either assigned left.x or right.x inside the transform
  971. sorting = [doc], or possibly [doc, wpos] if assignment self.wpos = left.wpos in transform
  972. stepping on [doc, wpos] is handled by adjusting the requested value by the maximum (delta1, delta2), since it is either assigned left/right. This should be a separate constant
  973. so the self.x := left.x can be optimized to delta1, but fairly insignificant.
  974. f) static = [doc, wpos] - from sort criteria, and field referenced in the proximity condition
  975. dynamic = [doc, wpos] after intersection with output from e.
  976. sorted by [doc, wpos, wip] again.
  977. More on JOIN:
  978. * Write code to allow nesting ((a JOIN b) JOIN c) with different deltas for each level.
  979. * Do all the seeks before creating any of the records. Probably need to find the first candidate in parallel, and then recursively create the transforms.
  980. seek(n) = seek(applyDelta(min(values[1..n-1], minRightBeforeLeft);
  981. if fail, adjust match, by minRightBeforeLeft, and start seeking on 1 again.
  982. once you've got a match, go off and create the instances.
  983. For arbitrary nesting
  984. (a w/x b) w/y (c w/z d)
  985. Seek(a)
  986. seek(b, matcha-x);
  987. seek(c, min(a,b)-(y+z));
  988. seek(d, c, z);
  989. could optionally check that (a, b) w/y (c, d), but probably better to just handle via the post filter.
  990. Indexes and subsort information:
  991. i := rawindex
  992. p := project(i, logicalindex);
  993. st := stepped(p, [a,b,c,d,e]);
  994. e := project(st, p2());
  995. f := compoundindexread;
  996. Need to locate stepped
  997. i) walk up to work out what is projected, and down. Probably simplest done using a recursive function - should be relatively simple. Don't merge with the index definition any more.
  998. ii) Implement should be ok. Have a flag to indicate if we spotted a STEPPED() identifier. Complain if not a read.
  999. Note:
  1000. for search "a and b and date > x" it is much better to step (a,b) first before date because of condition complexity
  1001. */