hqliter.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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 "jexcept.hpp"
  18. #include "jmisc.hpp"
  19. #include "javahash.hpp"
  20. #include "eclhelper.hpp"
  21. #include "hqlfunc.hpp"
  22. #include "hqlhtcpp.ipp"
  23. #include "hqlwcpp.hpp"
  24. #include "hqlcpputil.hpp"
  25. #include "hqlcerrors.hpp"
  26. #include "hqlcatom.hpp"
  27. #include "hqlpmap.hpp"
  28. #include "hqlthql.hpp"
  29. #include "hqlcset.ipp"
  30. #include "hqlfold.hpp"
  31. #include "hqltcppc.ipp"
  32. #include "hqlutil.hpp"
  33. #include "hqlcse.ipp"
  34. #include "hqliter.ipp"
  35. #include "hqlinline.hpp"
  36. //===========================================================================
  37. bool isSequenceRoot(IHqlExpression * expr)
  38. {
  39. switch (expr->getOperator())
  40. {
  41. case no_newkeyindex:
  42. case no_table:
  43. case no_select:
  44. return true;
  45. }
  46. return false;
  47. }
  48. bool canBuildSequenceInline(IHqlExpression * expr)
  49. {
  50. loop
  51. {
  52. switch (expr->getOperator())
  53. {
  54. case no_cachealias:
  55. expr = expr->queryChild(1);
  56. break;
  57. case no_newkeyindex:
  58. case no_table:
  59. case no_select:
  60. return true;
  61. case no_sorted:
  62. case no_distributed:
  63. case no_preservemeta:
  64. case no_grouped:
  65. case no_preload:
  66. case no_limit:
  67. case no_keyedlimit:
  68. case no_choosen:
  69. case no_filter:
  70. case no_hqlproject:
  71. case no_newusertable:
  72. case no_compound_diskread:
  73. case no_compound_disknormalize:
  74. case no_compound_diskaggregate:
  75. case no_compound_diskcount:
  76. case no_compound_diskgroupaggregate:
  77. case no_compound_indexread:
  78. case no_compound_indexnormalize:
  79. case no_compound_indexaggregate:
  80. case no_compound_indexcount:
  81. case no_compound_indexgroupaggregate:
  82. case no_compound_childread:
  83. case no_compound_childnormalize:
  84. case no_compound_childaggregate:
  85. case no_compound_childcount:
  86. case no_compound_childgroupaggregate:
  87. case no_compound_fetch:
  88. case no_compound_selectnew:
  89. case no_compound_inline:
  90. case no_alias_scope:
  91. case no_dataset_alias:
  92. expr = expr->queryChild(0);
  93. break;
  94. default:
  95. return false;
  96. }
  97. }
  98. }
  99. //-------------------------------------------------------------------
  100. void TransformSequenceBuilder::buildSequence(BuildCtx & ctx, BuildCtx * declarectx, IHqlExpression * expr)
  101. {
  102. node_operator op = expr->getOperator();
  103. switch (op)
  104. {
  105. case no_cachealias:
  106. buildSequence(ctx, declarectx, expr->queryChild(1));
  107. return;
  108. case no_newkeyindex:
  109. case no_table:
  110. case no_fetch:
  111. case no_select:
  112. case no_anon:
  113. case no_pseudods:
  114. break;
  115. case no_hqlproject:
  116. case no_newusertable:
  117. buildSequence(ctx, NULL, expr->queryChild(0));
  118. break;
  119. default:
  120. buildSequence(ctx, declarectx, expr->queryChild(0));
  121. break;
  122. }
  123. switch (op)
  124. {
  125. case no_filter:
  126. {
  127. HqlExprAttr cond;
  128. ForEachChild(i, expr)
  129. {
  130. IHqlExpression * cur = queryRealChild(expr, i);
  131. if (cur && i != 0)
  132. extendConditionOwn(cond, no_and, LINK(cur));
  133. }
  134. OwnedHqlExpr test = getInverse(cond);
  135. if (translator.queryOptions().foldFilter)
  136. test.setown(foldScopedHqlExpression(translator.queryErrorProcessor(), expr->queryChild(0)->queryNormalizedSelector(), test));
  137. if (translator.queryOptions().spotCSE)
  138. test.setown(spotScalarCSE(test, NULL, translator.queryOptions().spotCseInIfDatasetConditions));
  139. translator.buildFilteredReturn(ctx, test, failedFilterValue);
  140. }
  141. break;
  142. case no_hqlproject:
  143. {
  144. IHqlExpression * dataset = expr->queryChild(0);
  145. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, querySelSeq(expr));
  146. OwnedHqlExpr newSelect = ensureActiveRow(dataset->queryNormalizedSelector());
  147. OwnedHqlExpr transform = replaceSelector(expr->queryChild(1), leftSelect, newSelect);
  148. //MORE: Calculate cses at this point, but we really need to have removed hqlprojects for cse to work...
  149. BuildCtx & createctx = declarectx ? *declarectx : ctx;
  150. Owned<BoundRow> tempRow = translator.declareTempAnonRow(createctx, ctx, expr);
  151. BuildCtx subctx(ctx);
  152. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL);
  153. translator.doInlineTransform(subctx, transform, tempRow);
  154. translator.bindTableCursor(ctx, expr, tempRow->queryBound());
  155. }
  156. break;
  157. case no_newusertable:
  158. {
  159. IHqlExpression * transform = expr->queryChild(2);
  160. BuildCtx & createctx = declarectx ? *declarectx : ctx;
  161. Owned<BoundRow> tempRow = translator.declareTempAnonRow(createctx, ctx, expr);
  162. BuildCtx subctx(ctx);
  163. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL);
  164. translator.doInlineTransform(subctx, transform, tempRow);
  165. translator.bindTableCursor(ctx, expr, tempRow->queryBound());
  166. }
  167. break;
  168. }
  169. }
  170. //------------------------------------------------------------------------------------------
  171. //Gather the different select levels, return the root dataset (if not in scope)
  172. IHqlExpression * gatherSelectorLevels(HqlExprArray & iterators, IHqlExpression * expr)
  173. {
  174. loop
  175. {
  176. IHqlExpression * root = queryRoot(expr);
  177. if (!root || root->getOperator() != no_select)
  178. return expr;
  179. iterators.add(*LINK(expr), 0);
  180. if (!root->hasAttribute(newAtom))
  181. return NULL;
  182. expr = root->queryChild(0);
  183. }
  184. }
  185. void CompoundIteratorBuilder::bindParentCursors(BuildCtx & ctx, CursorArray & cursors)
  186. {
  187. OwnedHqlExpr colocal = createQuoted("activity", makeVoidType());
  188. ForEachItemIn(i, cursors)
  189. {
  190. BoundRow & cur = cursors.item(i);
  191. //Very similar to code in the extract builder
  192. OwnedHqlExpr colocalBound = addMemberSelector(cur.queryBound(), colocal);
  193. ctx.associateOwn(*cur.clone(colocalBound));
  194. }
  195. }
  196. void CompoundIteratorBuilder::buildCompoundIterator(BuildCtx & initctx, HqlExprArray & iterators, CursorArray & cursors)
  197. {
  198. StringBuffer s;
  199. declarectx.addQuoted("RtlCompoundIterator iter;");
  200. initctx.addQuoted(s.clear().append("iter.init(").append(iterators.ordinality()).append(");"));
  201. ForEachItemIn(i, iterators)
  202. {
  203. StringBuffer iterName, cursorName;
  204. createSingleLevelIterator(iterName, cursorName, &iterators.item(i), cursors);
  205. initctx.addQuoted(s.clear().append("iter.addIter(").append(i).append(",&").append(iterName).append(",&").append(cursorName).append(");"));
  206. }
  207. }
  208. void CompoundIteratorBuilder::createSingleLevelIterator(StringBuffer & iterName, StringBuffer & cursorName, IHqlExpression * expr, CursorArray & cursors)
  209. {
  210. LinkedHqlExpr cur = expr;
  211. IHqlExpression * root = queryRoot(cur);
  212. assertex(root->getOperator() == no_select);
  213. //First remove any new attributes from selector, since parent cursor is guaranteed to be in scope at this point.
  214. IHqlExpression * normalized = root->queryNormalizedSelector();
  215. if (root != normalized)
  216. cur.setown(replaceExpression(cur, root, normalized));
  217. createSingleIterator(iterName, cur, cursors);
  218. translator.getUniqueId(cursorName.append("row"));
  219. OwnedHqlExpr row = createVariable(cursorName, makeRowReferenceType(cur));
  220. declarectx.addDeclare(row);
  221. cursors.append(*translator.createTableCursor(cur, row, no_none, NULL));
  222. }
  223. void CompoundIteratorBuilder::createSingleIterator(StringBuffer & iterName, IHqlExpression * expr, CursorArray & cursors)
  224. {
  225. StringBuffer s;
  226. translator.getUniqueId(iterName.clear().append("iter"));
  227. //MORE: Nested class/...
  228. BuildCtx classctx(nestedctx);
  229. translator.beginNestedClass(classctx, iterName, "IRtlDatasetSimpleCursor", NULL, NULL);
  230. translator.queryEvalContext(classctx)->ensureHelpersExist();
  231. if (isArrayRowset(expr->queryType()))
  232. {
  233. classctx.addQuoted("byte * * end;");
  234. classctx.addQuoted("byte * * cur;");
  235. }
  236. else
  237. {
  238. classctx.addQuoted("byte * end;");
  239. classctx.addQuoted("byte * cur;");
  240. }
  241. IHqlExpression * root = queryRoot(expr);
  242. if (expr->queryBody() == root)
  243. {
  244. BuildCtx firstctx(classctx);
  245. firstctx.addQuotedCompound("virtual const byte * first()");
  246. createRawFirstFunc(firstctx, expr, cursors);
  247. BuildCtx nextctx(classctx);
  248. nextctx.addQuotedCompound("virtual const byte * next()");
  249. createRawNextFunc(nextctx, expr, cursors);
  250. }
  251. else
  252. {
  253. BuildCtx rawfirstctx(classctx);
  254. rawfirstctx.addQuotedCompound("inline const byte * rawFirst()");
  255. createRawFirstFunc(rawfirstctx, root, cursors);
  256. BuildCtx rawnextctx(classctx);
  257. rawnextctx.addQuotedCompound("virtual const byte * rawNext()");
  258. createRawNextFunc(rawnextctx, root, cursors);
  259. OwnedHqlExpr failValue = createTranslatedOwned(createValue(no_nullptr, makeVoidType()));
  260. TransformSequenceBuilder checkValidBuilder(translator, failValue);
  261. BuildCtx checkctx(classctx);
  262. checkctx.addQuotedCompound("inline const byte * checkValid()");
  263. bindParentCursors(checkctx, cursors);
  264. if (isArrayRowset(expr->queryType()))
  265. translator.bindTableCursor(checkctx, root, "(*cur)");
  266. else
  267. translator.bindTableCursor(checkctx, root, "cur");
  268. checkValidBuilder.buildSequence(checkctx, &classctx, expr);
  269. BoundRow * match = translator.resolveSelectorDataset(checkctx, expr);
  270. assertex(match);
  271. OwnedHqlExpr row = getPointer(match->queryBound());
  272. checkctx.addReturn(row);
  273. BuildCtx firstctx(classctx);
  274. firstctx.addQuotedCompound("virtual const byte * first()");
  275. firstctx.addQuoted("if (!rawFirst()) return NULL;");
  276. firstctx.addQuotedCompound("for (;;)");
  277. firstctx.addQuoted("const byte * valid = checkValid(); if (valid) return valid;");
  278. firstctx.addQuoted("if (!rawNext()) return NULL;");
  279. BuildCtx nextctx(classctx);
  280. nextctx.addQuotedCompound("virtual const byte * next()");
  281. nextctx.addQuotedCompound("for (;;)");
  282. nextctx.addQuoted("if (!rawNext()) return NULL;");
  283. nextctx.addQuoted("const byte * valid = checkValid(); if (valid) return valid;");
  284. }
  285. translator.endNestedClass();
  286. }
  287. void CompoundIteratorBuilder::createRawFirstFunc(BuildCtx & ctx, IHqlExpression * expr, CursorArray & cursors)
  288. {
  289. bool isOutOfLine = isArrayRowset(expr->queryType());
  290. bindParentCursors(ctx, cursors);
  291. CHqlBoundExpr boundDs;
  292. translator.buildDataset(ctx, expr, boundDs, queryNaturalFormat(expr->queryType()));
  293. if (isOutOfLine)
  294. {
  295. StringBuffer s;
  296. s.clear().append("cur = "); // more: should really be const...
  297. translator.generateExprCpp(s, boundDs.expr).append(";");
  298. ctx.addQuoted(s);
  299. OwnedHqlExpr count = translator.getBoundCount(boundDs);
  300. s.clear().append("end = cur+");
  301. translator.generateExprCpp(s, count).append(";");
  302. ctx.addQuoted(s);
  303. ctx.addQuoted("return (cur < end) ? *cur : NULL;");
  304. }
  305. else
  306. {
  307. OwnedHqlExpr address = getPointer(boundDs.expr);
  308. StringBuffer s;
  309. s.clear().append("cur = (byte *)"); // more: should really be const...
  310. translator.generateExprCpp(s, address).append(";");
  311. ctx.addQuoted(s);
  312. OwnedHqlExpr length = translator.getBoundLength(boundDs);
  313. s.clear().append("end = cur+");
  314. translator.generateExprCpp(s, length).append(";");
  315. ctx.addQuoted(s);
  316. ctx.addQuoted("return (cur < end) ? cur : NULL;");
  317. }
  318. }
  319. void CompoundIteratorBuilder::createRawNextFunc(BuildCtx & ctx, IHqlExpression * expr, CursorArray & cursors)
  320. {
  321. if (isArrayRowset(expr->queryType()))
  322. {
  323. ctx.addQuoted("cur++;");
  324. ctx.addQuoted("return (cur < end) ? *cur : NULL;");
  325. }
  326. else
  327. {
  328. bindParentCursors(ctx, cursors);
  329. translator.bindTableCursor(ctx, expr, "cur");
  330. CHqlBoundExpr bound;
  331. translator.getRecordSize(ctx, expr, bound);
  332. StringBuffer s;
  333. s.clear().append("cur+=");
  334. translator.generateExprCpp(s, bound.expr).append(";");
  335. ctx.addQuoted(s);
  336. ctx.addQuoted("return (cur < end) ? cur : NULL;");
  337. }
  338. }
  339. //------------------------------------------------------------------------------------------