hqlcset.cpp 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998
  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 "jexcept.hpp"
  19. #include "jmisc.hpp"
  20. #include "javahash.hpp"
  21. #include "eclhelper.hpp"
  22. #include "hqlfunc.hpp"
  23. #include "hqlattr.hpp"
  24. #include "hqlhtcpp.ipp"
  25. #include "hqlwcpp.hpp"
  26. #include "hqlcpputil.hpp"
  27. #include "hqlcerrors.hpp"
  28. #include "hqlcatom.hpp"
  29. #include "hqlpmap.hpp"
  30. #include "hqlthql.hpp"
  31. #include "hqlcset.ipp"
  32. #include "hqlfold.hpp"
  33. #include "hqltcppc.ipp"
  34. #include "hqlutil.hpp"
  35. #include "hqliter.ipp"
  36. #ifdef CREATE_DEAULT_ROW_IF_NULL
  37. #define CREATE_DEAULT_ROW_IF_NULL_VALUE 1
  38. #else
  39. #define CREATE_DEAULT_ROW_IF_NULL_VALUE 0
  40. #endif
  41. //===========================================================================
  42. IHqlExpression * getOutOfRangeValue(IHqlExpression * indexExpr)
  43. {
  44. IHqlExpression * dft = indexExpr->queryProperty(defaultAtom);
  45. if (dft)
  46. return LINK(dft->queryChild(0));
  47. else
  48. return createNullExpr(indexExpr);
  49. }
  50. //===========================================================================
  51. BaseDatasetCursor::BaseDatasetCursor(HqlCppTranslator & _translator, IHqlExpression * _ds, CHqlBoundExpr * _boundDs) : translator(_translator)
  52. {
  53. ds.set(_ds);
  54. record.set(ds->queryRecord());
  55. if (_boundDs)
  56. boundDs.set(*_boundDs);
  57. }
  58. BoundRow * BaseDatasetCursor::buildIterateLoop(BuildCtx & ctx, bool needToBreak)
  59. {
  60. StringBuffer iterName;
  61. buildIterateClass(ctx, iterName, NULL);
  62. StringBuffer s, rowName;
  63. OwnedHqlExpr row = createRow(ctx, "row", rowName, false);
  64. //row = iter.first()
  65. s.clear().append(rowName).append(" = ").append(iterName).append(".first();");
  66. ctx.addQuoted(s);
  67. //while (row)
  68. ctx.addLoop(row, NULL, false);
  69. BoundRow * cursor = translator.bindTableCursor(ctx, ds, row);
  70. // row = iter.next();
  71. ctx.setNextDestructor();
  72. s.clear().append(rowName).append(" = (byte *)").append(iterName).append(".next();");
  73. ctx.addQuoted(s);
  74. return cursor;
  75. }
  76. void BaseDatasetCursor::buildIterateClass(BuildCtx & ctx, SharedHqlExpr & iter, SharedHqlExpr & row)
  77. {
  78. StringBuffer cursorName, rowName;
  79. buildIterateClass(ctx, cursorName, NULL);
  80. iter.setown(createVariable(cursorName.str(), makeBoolType()));
  81. row.setown(createRow(ctx, "row", rowName, false));
  82. }
  83. void BaseDatasetCursor::buildIterateMembers(BuildCtx & declarectx, BuildCtx & initctx)
  84. {
  85. StringBuffer iterName;
  86. buildIterateClass(declarectx, iterName, &initctx);
  87. StringBuffer s, rowName;
  88. OwnedHqlExpr row = createRow(declarectx, "row", rowName, false);
  89. //row = iter.first()
  90. BuildCtx firstctx(declarectx);
  91. firstctx.addQuotedCompound("virtual bool first()");
  92. s.clear().append(rowName).append(" = (byte *)").append(iterName).append(".first();");
  93. firstctx.addQuoted(s);
  94. s.clear().append("return ").append(rowName).append(" != NULL;");
  95. firstctx.addQuoted(s);
  96. //row = iter.first()
  97. BuildCtx nextctx(declarectx);
  98. nextctx.addQuotedCompound("virtual bool next()");
  99. s.clear().append(rowName).append(" = (byte *)").append(iterName).append(".next();");
  100. nextctx.addQuoted(s);
  101. s.clear().append("return ").append(rowName).append(" != NULL;");
  102. nextctx.addQuoted(s);
  103. //iterate
  104. translator.bindTableCursor(declarectx, ds, row);
  105. }
  106. BoundRow * BaseDatasetCursor::buildSelectMap(BuildCtx & ctx, IHqlExpression * indexExpr)
  107. {
  108. // Should only be seen for dictionaries
  109. throwUnexpected();
  110. }
  111. BoundRow * BaseDatasetCursor::buildSelectNth(BuildCtx & ctx, IHqlExpression * indexExpr)
  112. {
  113. //MORE: Check if the cursor already exists....
  114. StringBuffer cursorName;
  115. buildIterateClass(ctx, cursorName, NULL);
  116. bool conditional = !indexExpr->hasProperty(noBoundCheckAtom);
  117. //create a unique dataset and associate it with a call to select
  118. //set value to be the field selection from the dataset
  119. StringBuffer s, rowName;
  120. OwnedHqlExpr row = createRow(ctx, "row", rowName, conditional && CREATE_DEAULT_ROW_IF_NULL_VALUE);
  121. CHqlBoundExpr boundIndex;
  122. OwnedHqlExpr index = adjustIndexBaseToZero(indexExpr->queryChild(1));
  123. translator.buildExpr(ctx, index, boundIndex);
  124. //MORE: CREATE_DEAULT_ROW_IF_NULL - pass the default row to the select() function.
  125. //row = iter.select(n)
  126. s.clear().append(rowName).append(" = (byte *)").append(cursorName).append(".select(");
  127. translator.generateExprCpp(s, boundIndex.expr);
  128. s.append(");");
  129. ctx.addQuoted(s);
  130. #ifdef CREATE_DEAULT_ROW_IF_NULL
  131. if (conditional)
  132. {
  133. CHqlBoundExpr boundCleared;
  134. translator.buildDefaultRow(ctx, ds, boundCleared);
  135. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  136. BuildCtx subctx(ctx);
  137. OwnedHqlExpr test = createValue(no_not, makeBoolType(), LINK(row));
  138. subctx.addFilter(test);
  139. subctx.addAssign(row, defaultRowPtr);
  140. conditional = false;
  141. }
  142. #endif
  143. BoundRow * cursor = translator.bindRow(ctx, indexExpr, row);
  144. cursor->setConditional(conditional);
  145. return cursor;
  146. }
  147. IHqlExpression * BaseDatasetCursor::createRow(BuildCtx & ctx, const char * prefix, StringBuffer & rowName, bool conditional)
  148. {
  149. translator.getUniqueId(rowName.append(prefix));
  150. OwnedITypeInfo type;
  151. if (boundDs.expr && boundDs.expr->queryRecord())
  152. type.setown(makeConstantModifier(makeRowReferenceType(boundDs)));
  153. else
  154. type.setown(makeConstantModifier(makeRowReferenceType(ds)));
  155. if (conditional)
  156. type.setown(setLinkCountedAttr(type, false));
  157. OwnedHqlExpr row = createVariable(rowName, type.getClear());
  158. ctx.addDeclare(row);
  159. return row.getClear();
  160. }
  161. //---------------------------------------------------------------------------
  162. BlockDatasetCursor::BlockDatasetCursor(HqlCppTranslator & _translator, IHqlExpression * _ds, CHqlBoundExpr & _boundDs) : BaseDatasetCursor(_translator, _ds, &_boundDs)
  163. {
  164. boundDs.set(_boundDs);
  165. assertex(boundDs.expr->isDatarow() || !isArrayRowset(boundDs.expr->queryType())); // I don't think this can ever be called at the moment
  166. }
  167. void BlockDatasetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  168. {
  169. tgt.expr.setown(translator.getBoundCount(boundDs));
  170. }
  171. void BlockDatasetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  172. {
  173. if (boundDs.count)
  174. tgt.expr.setown(createValue(no_ne, makeBoolType(), LINK(boundDs.count), getZero()));
  175. else
  176. tgt.expr.setown(createValue(no_ne, makeBoolType(), LINK(boundDs.length), getZero()));
  177. }
  178. void BlockDatasetCursor::buildIterateClass(BuildCtx & ctx, StringBuffer & cursorName, BuildCtx * initctx)
  179. {
  180. translator.getUniqueId(cursorName.append("iter"));
  181. StringBuffer extraParams;
  182. StringBuffer decl,args;
  183. if (translator.isFixedRecordSize(record))
  184. {
  185. //RtlFixedDatasetCursor cursor(len, data, size)
  186. decl.append("RtlFixedDatasetCursor");
  187. extraParams.append(", ").append(translator.getFixedRecordSize(record));
  188. }
  189. else
  190. {
  191. //RtlVariableDatasetCursor cursor(len, data, recordSize)
  192. decl.append("RtlVariableDatasetCursor");
  193. translator.buildMetaForRecord(extraParams.append(", "), record);
  194. }
  195. OwnedHqlExpr size = translator.getBoundSize(boundDs);
  196. decl.append(" ").append(cursorName);
  197. translator.generateExprCpp(args, size);
  198. args.append(", ");
  199. translator.generateExprCpp(args, boundDs.expr);
  200. args.append(extraParams);
  201. if (initctx)
  202. {
  203. StringBuffer s;
  204. s.append(cursorName).append(".init(").append(args).append(");");
  205. initctx->addQuoted(s);
  206. }
  207. else
  208. {
  209. decl.append("(").append(args).append(")");
  210. }
  211. decl.append(";");
  212. ctx.addQuoted(decl);
  213. }
  214. //---------------------------------------------------------------------------
  215. bool isEmptyDataset(const CHqlBoundExpr & bound)
  216. {
  217. IValue * value = NULL;
  218. if (bound.length)
  219. value = bound.length->queryValue();
  220. else if (bound.count)
  221. value = bound.count->queryValue();
  222. return (value && value->getIntValue() == 0);
  223. }
  224. InlineBlockDatasetCursor::InlineBlockDatasetCursor(HqlCppTranslator & _translator, IHqlExpression * _ds, CHqlBoundExpr & _boundDs) : BlockDatasetCursor(_translator, _ds, _boundDs)
  225. {
  226. }
  227. BoundRow * InlineBlockDatasetCursor::buildIterateLoop(BuildCtx & ctx, bool needToBreak)
  228. {
  229. StringBuffer rowName;
  230. OwnedHqlExpr row = createRow(ctx, "row", rowName, false);
  231. if (isEmptyDataset(boundDs))
  232. {
  233. ctx.addFilter(queryBoolExpr(false));
  234. return translator.bindTableCursor(ctx, ds, row);
  235. }
  236. StringBuffer s;
  237. //row = ds;
  238. OwnedHqlExpr address = getPointer(boundDs.expr);
  239. OwnedHqlExpr cast = createValue(no_implicitcast, row->getType(), LINK(address));
  240. ctx.addAssign(row, cast);
  241. OwnedHqlExpr test;
  242. if (boundDs.length)
  243. {
  244. OwnedHqlExpr length = translator.getBoundLength(boundDs);
  245. StringBuffer endName;
  246. OwnedHqlExpr end = createRow(ctx, "end", endName, false);
  247. //end = row+length;
  248. s.clear().append(endName).append(" = ").append(rowName).append("+");
  249. translator.generateExprCpp(s, length).append(";");
  250. ctx.addQuoted(s);
  251. //while (row < end)
  252. test.setown(createValue(no_lt, makeBoolType(), LINK(row), LINK(end)));
  253. }
  254. else if (matchesConstantValue(boundDs.count, 1) && !needToBreak)
  255. {
  256. //Optimize count=1, needToBreak = false;
  257. ctx.addGroup();
  258. return translator.bindTableCursor(ctx, ds, row);
  259. }
  260. else
  261. {
  262. OwnedHqlExpr count = translator.getBoundCount(boundDs);
  263. //count = <n>
  264. OwnedHqlExpr counter = ctx.getTempDeclare(unsignedType, count);
  265. //while (count--)
  266. test.setown(createValue(no_postdec, LINK(counter)));
  267. }
  268. ctx.addLoop(test, NULL, false);
  269. BoundRow * cursor = translator.bindTableCursor(ctx, ds, row);
  270. //row = row + recordSize
  271. OwnedHqlExpr size = translator.getRecordSize(cursor->querySelector());
  272. CHqlBoundExpr boundSize;
  273. translator.buildExpr(ctx, size, boundSize);
  274. ctx.setNextDestructor();
  275. if (translator.queryOptions().optimizeIncrement)
  276. {
  277. ctx.addAssignIncrement(row, boundSize.expr);
  278. }
  279. else
  280. {
  281. OwnedHqlExpr inc = createValue(no_add, row->getType(), LINK(row), LINK(boundSize.expr));
  282. ctx.addAssign(row, inc);
  283. }
  284. return cursor;
  285. }
  286. BoundRow * InlineBlockDatasetCursor::buildSelectFirst(BuildCtx & ctx, IHqlExpression * indexExpr, bool createDefaultRowIfNull)
  287. {
  288. StringBuffer s, rowName;
  289. bool conditional = !indexExpr->hasProperty(noBoundCheckAtom);
  290. OwnedHqlExpr row = createRow(ctx, "row", rowName, (conditional && createDefaultRowIfNull));
  291. BuildCtx subctx(ctx);
  292. if (conditional)
  293. {
  294. HqlExprAttr test;
  295. if (boundDs.count)
  296. {
  297. IValue * countValue = boundDs.count->queryValue();
  298. if (countValue)
  299. {
  300. if (countValue->getIntValue() == 0)
  301. return NULL;
  302. }
  303. else
  304. {
  305. OwnedHqlExpr max = createTranslated(boundDs.count);
  306. test.setown(createCompare(no_ne, max, queryZero()));
  307. }
  308. }
  309. else
  310. {
  311. OwnedHqlExpr max = createTranslated(boundDs.length);
  312. test.setown(createCompare(no_gt, max, queryZero()));
  313. }
  314. if (test)
  315. {
  316. CHqlBoundExpr boundCleared;
  317. if (createDefaultRowIfNull)
  318. {
  319. translator.buildDefaultRow(ctx, ds, boundCleared);
  320. conditional = false;
  321. }
  322. else
  323. translator.buildNullRow(ctx, ds, boundCleared);
  324. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  325. ctx.addAssign(row, defaultRowPtr);
  326. translator.buildFilter(subctx, test);
  327. }
  328. else
  329. conditional = false;
  330. }
  331. if (isArrayRowset(boundDs.expr->queryType()))
  332. {
  333. s.clear().append(rowName).append(" = ");
  334. translator.generateExprCpp(s, boundDs.expr).append("[0];");
  335. subctx.addQuoted(s);
  336. }
  337. else
  338. {
  339. OwnedHqlExpr address = getPointer(boundDs.expr);
  340. s.clear().append(rowName).append(" = (byte *)(void *)"); // more: should really be const...
  341. translator.generateExprCpp(s, address);
  342. s.append(";");
  343. subctx.addQuoted(s);
  344. }
  345. BoundRow * cursor = translator.bindRow(ctx, indexExpr, row);
  346. cursor->setConditional(conditional);
  347. return cursor;
  348. }
  349. BoundRow * InlineBlockDatasetCursor::buildSelectNth(BuildCtx & ctx, IHqlExpression * indexExpr)
  350. {
  351. assertex(!isArrayRowset(boundDs.expr->queryType())); // I don't think this can ever be called at the moment
  352. OwnedHqlExpr index = foldHqlExpression(indexExpr->queryChild(1));
  353. if (!translator.isFixedRecordSize(record))
  354. {
  355. if (matchesConstantValue(index, 1))
  356. return buildSelectFirst(ctx, indexExpr, CREATE_DEAULT_ROW_IF_NULL_VALUE);
  357. return BlockDatasetCursor::buildSelectNth(ctx, indexExpr);
  358. }
  359. if (matchesConstantValue(index, 1))
  360. return buildSelectFirst(ctx, indexExpr, CREATE_DEAULT_ROW_IF_NULL_VALUE);
  361. bool conditional = !indexExpr->hasProperty(noBoundCheckAtom);
  362. //row = NULL
  363. StringBuffer s, rowName;
  364. OwnedHqlExpr row = createRow(ctx, "row", rowName, (conditional && CREATE_DEAULT_ROW_IF_NULL_VALUE));
  365. //if (index > 0 && (index <= count) or (index * fixedSize <= size)
  366. //MORE: Need to be very careful about the types...
  367. OwnedHqlExpr base0Index;
  368. unsigned fixedSize = translator.getFixedRecordSize(record);
  369. BuildCtx subctx(ctx);
  370. if (conditional)
  371. {
  372. OwnedHqlExpr simpleIndex = translator.buildSimplifyExpr(ctx, index);
  373. base0Index.setown(adjustIndexBaseToZero(simpleIndex));
  374. IValue * indexValue = index->queryValue();
  375. OwnedHqlExpr test;
  376. if (indexValue)
  377. {
  378. if (indexValue->getIntValue() <= 0)
  379. return NULL;
  380. }
  381. else
  382. test.setown(createCompare(no_gt, simpleIndex, queryZero()));
  383. IHqlExpression * test2 = NULL;
  384. if (boundDs.count)
  385. {
  386. IValue * countValue = boundDs.count->queryValue();
  387. if (countValue && indexValue)
  388. {
  389. if (indexValue->getIntValue() > countValue->getIntValue())
  390. return NULL;
  391. }
  392. else
  393. {
  394. OwnedHqlExpr max = createTranslated(boundDs.count);
  395. test2 = createCompare(no_le, simpleIndex, max);
  396. }
  397. }
  398. else
  399. {
  400. OwnedHqlExpr max = createTranslated(boundDs.length);
  401. OwnedHqlExpr offset = multiplyValue(simpleIndex, fixedSize);
  402. test2 = createCompare(no_le, offset, max);
  403. }
  404. extendConditionOwn(test, no_and, test2);
  405. if (test)
  406. {
  407. CHqlBoundExpr boundCleared;
  408. #ifdef CREATE_DEAULT_ROW_IF_NULL
  409. translator.buildDefaultRow(ctx, ds, boundCleared);
  410. conditional = false;
  411. #else
  412. translator.buildNullRow(ctx, ds, boundCleared);
  413. #endif
  414. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  415. ctx.addAssign(row, defaultRowPtr);
  416. translator.buildFilter(subctx, test);
  417. }
  418. else
  419. conditional = false;
  420. }
  421. else
  422. {
  423. CHqlBoundExpr boundIndex;
  424. OwnedHqlExpr base0 = adjustIndexBaseToZero(index);
  425. translator.buildExpr(ctx, base0, boundIndex);
  426. base0Index.setown(boundIndex.getTranslatedExpr());
  427. }
  428. //row = base + index * fixedSize;
  429. OwnedHqlExpr address = LINK(boundDs.expr);//getPointer(boundDs.expr);
  430. s.clear().append(rowName).append(" = (byte *)(void *)"); // more: should really be const...
  431. translator.generateExprCpp(s, address);
  432. CHqlBoundExpr boundOffset;
  433. OwnedHqlExpr offset = multiplyValue(base0Index, fixedSize);
  434. translator.buildExpr(subctx, offset, boundOffset);
  435. s.append(" + (");
  436. translator.generateExprCpp(s, boundOffset.expr).append(")");
  437. s.append(";");
  438. subctx.addQuoted(s);
  439. BoundRow * cursor = translator.bindRow(ctx, indexExpr, row);
  440. cursor->setConditional(conditional);
  441. return cursor;
  442. }
  443. //---------------------------------------------------------------------------
  444. InlineLinkedDatasetCursor::InlineLinkedDatasetCursor(HqlCppTranslator & _translator, IHqlExpression * _ds, CHqlBoundExpr & _boundDs) : BaseDatasetCursor(_translator, _ds, &_boundDs)
  445. {
  446. assertex(boundDs.count != NULL);
  447. assertex(isArrayRowset(boundDs.expr->queryType()));
  448. }
  449. void InlineLinkedDatasetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  450. {
  451. tgt.expr.set(boundDs.count);
  452. }
  453. void InlineLinkedDatasetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  454. {
  455. tgt.expr.setown(createValue(no_ne, makeBoolType(), LINK(boundDs.count), getZero()));
  456. }
  457. void InlineLinkedDatasetCursor::buildIterateClass(BuildCtx & ctx, StringBuffer & cursorName, BuildCtx * initctx)
  458. {
  459. translator.getUniqueId(cursorName.append("iter"));
  460. //RtlFixedDatasetCursor cursor(len, data, size)
  461. StringBuffer decl;
  462. decl.append("RtlLinkedDatasetCursor ").append(cursorName);
  463. StringBuffer args;
  464. translator.generateExprCpp(args, boundDs.count);
  465. args.append(", ");
  466. translator.generateExprCpp(args, boundDs.expr);
  467. if (initctx)
  468. {
  469. StringBuffer s;
  470. s.append(cursorName).append(".init(").append(args).append(");");
  471. initctx->addQuoted(s);
  472. }
  473. else
  474. {
  475. decl.append("(").append(args).append(")");
  476. }
  477. decl.append(";");
  478. ctx.addQuoted(decl);
  479. }
  480. BoundRow * InlineLinkedDatasetCursor::buildIterateLoop(BuildCtx & ctx, bool needToBreak)
  481. {
  482. StringBuffer rowName;
  483. OwnedHqlExpr row = createRow(ctx, "row", rowName, false);
  484. if (isEmptyDataset(boundDs))
  485. {
  486. ctx.addFilter(queryBoolExpr(false));
  487. return translator.bindTableCursor(ctx, ds, row);
  488. }
  489. if (matchesConstantValue(boundDs.count, 1) && !needToBreak)
  490. {
  491. CHqlBoundExpr boundRow;
  492. boundRow.set(boundDs);
  493. translator.convertBoundDatasetToFirstRow(ds, boundRow);
  494. //Optimize count=1, needToBreak = false;
  495. ctx.addGroup();
  496. return translator.bindTableCursor(ctx, ds, boundRow.expr);
  497. }
  498. StringBuffer cursorName, s;
  499. translator.getUniqueId(cursorName.append("cur"));
  500. //row = ds;
  501. OwnedHqlExpr address = getPointer(boundDs.expr); // ensure no longer a wrapped item
  502. s.clear().append("byte * * ").append(cursorName).append(" = ");
  503. translator.generateExprCpp(s, address).append(";");
  504. ctx.addQuoted(s);
  505. OwnedHqlExpr test;
  506. OwnedHqlExpr count = translator.getBoundCount(boundDs);
  507. //count = <n>
  508. OwnedHqlExpr counter = ctx.getTempDeclare(unsignedType, count);
  509. //while (count--)
  510. test.setown(createValue(no_postdec, LINK(counter)));
  511. ctx.addLoop(test, NULL, false);
  512. ctx.addQuoted(s.clear().append(rowName).append(" = *").append(cursorName).append("++;"));
  513. BoundRow * cursor = translator.bindTableCursor(ctx, ds, row);
  514. return cursor;
  515. }
  516. BoundRow * InlineLinkedDatasetCursor::buildSelectNth(BuildCtx & ctx, IHqlExpression * indexExpr)
  517. {
  518. OwnedHqlExpr index = foldHqlExpression(indexExpr->queryChild(1));
  519. bool conditional = !indexExpr->hasProperty(noBoundCheckAtom);
  520. //row = NULL
  521. StringBuffer s, rowName;
  522. OwnedHqlExpr row = createRow(ctx, "row", rowName, (conditional && CREATE_DEAULT_ROW_IF_NULL_VALUE));
  523. //if (index > 0 && (index <= count)
  524. //MORE: Need to be very careful about the types...
  525. CHqlBoundExpr boundBase0Index;
  526. BuildCtx subctx(ctx);
  527. if (conditional)
  528. {
  529. IValue * indexValue = index->queryValue();
  530. if (indexValue)
  531. {
  532. if (indexValue->getIntValue() <= 0)
  533. return NULL;
  534. if (indexValue->getIntValue() > (size32_t)-1)
  535. return NULL;
  536. if (indexValue->queryType()->getSize() > sizeof(size32_t))
  537. index.setown(ensureExprType(index, sizetType));
  538. }
  539. OwnedHqlExpr simpleIndex = translator.buildSimplifyExpr(ctx, index);
  540. OwnedHqlExpr base0Index = adjustIndexBaseToZero(simpleIndex);
  541. translator.buildExpr(ctx, base0Index, boundBase0Index);
  542. OwnedHqlExpr test;
  543. if (!indexValue)
  544. test.setown(createCompare(no_gt, simpleIndex, queryZero()));
  545. IHqlExpression * test2 = NULL;
  546. IValue * countValue = boundDs.count->queryValue();
  547. if (countValue && indexValue)
  548. {
  549. if (indexValue->getIntValue() > countValue->getIntValue())
  550. return NULL;
  551. }
  552. else
  553. {
  554. OwnedHqlExpr max = createTranslated(boundDs.count);
  555. test2 = createCompare(no_le, simpleIndex, max);
  556. }
  557. extendConditionOwn(test, no_and, test2);
  558. if (test)
  559. {
  560. CHqlBoundExpr boundCleared;
  561. #ifdef CREATE_DEAULT_ROW_IF_NULL
  562. translator.buildDefaultRow(ctx, ds, boundCleared);
  563. conditional = false;
  564. #else
  565. translator.buildNullRow(ctx, ds, boundCleared);
  566. #endif
  567. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  568. ctx.addAssign(row, defaultRowPtr);
  569. translator.buildFilter(subctx, test);
  570. }
  571. else
  572. conditional = false;
  573. }
  574. else
  575. {
  576. OwnedHqlExpr base0 = adjustIndexBaseToZero(index);
  577. translator.buildExpr(ctx, base0, boundBase0Index);
  578. }
  579. //row = base[index]
  580. OwnedHqlExpr address = getPointer(boundDs.expr);
  581. OwnedHqlExpr indexedValue = createValue(no_index, row->getType(), LINK(address), LINK(boundBase0Index.expr));
  582. subctx.addAssign(row, indexedValue);
  583. //MORE: Should mark as linked if it is.
  584. BoundRow * cursor = translator.bindRow(ctx, indexExpr, row);
  585. cursor->setConditional(conditional);
  586. return cursor;
  587. }
  588. //---------------------------------------------------------------------------
  589. InlineLinkedDictionaryCursor::InlineLinkedDictionaryCursor(HqlCppTranslator & _translator, IHqlExpression * _ds, CHqlBoundExpr & _boundDs)
  590. : InlineLinkedDatasetCursor(_translator, _ds, _boundDs)
  591. {
  592. }
  593. BoundRow * InlineLinkedDictionaryCursor::buildSelectMap(BuildCtx & ctx, IHqlExpression * mapExpr)
  594. {
  595. Owned<BoundRow> tempRow = translator.declareLinkedRow(ctx, mapExpr, false);
  596. IHqlExpression *record = ds->queryRecord();
  597. StringBuffer lookupHelperName;
  598. OwnedHqlExpr dict = createDictionary(no_null, LINK(record));
  599. translator.buildDictionaryHashClass(ctx, record, dict, lookupHelperName);
  600. CHqlBoundTarget target;
  601. target.expr.set(tempRow->queryBound());
  602. HqlExprArray args;
  603. args.append(*createQuoted(lookupHelperName, makeBoolType()));
  604. args.append(*LINK(mapExpr->queryChild(0)));
  605. args.append(*LINK(mapExpr->queryChild(1)));
  606. args.append(*::createRow(no_null, LINK(record)));
  607. Owned<ITypeInfo> resultType = makeReferenceModifier(makeAttributeModifier(makeRowType(record->getType()), getLinkCountedAttr()));
  608. OwnedHqlExpr call = translator.bindFunctionCall(dictionaryLookupAtom, args, resultType);
  609. translator.buildExprAssign(ctx, target, call);
  610. return tempRow.getClear();
  611. }
  612. //---------------------------------------------------------------------------
  613. MultiLevelDatasetCursor::MultiLevelDatasetCursor(HqlCppTranslator & _translator, IHqlExpression * _ds)
  614. : BaseDatasetCursor(_translator, _ds, NULL)
  615. {
  616. }
  617. void MultiLevelDatasetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  618. {
  619. throwUnexpected();
  620. }
  621. void MultiLevelDatasetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  622. {
  623. throwUnexpected();
  624. }
  625. BoundRow * MultiLevelDatasetCursor::buildIterateLoop(BuildCtx & ctx, bool needToBreak)
  626. {
  627. OwnedHqlExpr breakVar;
  628. if (needToBreak)
  629. {
  630. CHqlBoundTarget bound;
  631. translator.createTempFor(ctx, boolType, bound, typemod_none, FormatNatural);
  632. breakVar.set(bound.expr);
  633. ctx.addAssign(breakVar, queryBoolExpr(false));
  634. }
  635. return doBuildIterateLoop(ctx, ds, breakVar, true);
  636. }
  637. BoundRow * MultiLevelDatasetCursor::buildSelectNth(BuildCtx & ctx, IHqlExpression * indexExpr)
  638. {
  639. //Declare row for final level, iterate the appropriate number of times, and then assign and break.
  640. BuildCtx initctx(ctx);
  641. IHqlExpression * selector = ds->queryNormalizedSelector();
  642. StringBuffer cursorName;
  643. translator.getUniqueId(cursorName.append("row"));
  644. OwnedHqlExpr rowExpr = createVariable(cursorName, makeRowReferenceType(selector));
  645. initctx.addDeclare(rowExpr);
  646. CHqlBoundExpr boundCleared;
  647. translator.buildDefaultRow(initctx, selector, boundCleared);
  648. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  649. initctx.addAssign(rowExpr, defaultRowPtr);
  650. HqlExprAssociation * savedMarker = ctx.associateExpr(queryConditionalRowMarker(), rowExpr);
  651. CHqlBoundTarget boundCount;
  652. IHqlExpression * index = indexExpr->queryChild(1);
  653. bool selectFirst = matchesConstValue(index, 1);
  654. if (!selectFirst)
  655. {
  656. translator.createTempFor(initctx, index, boundCount);
  657. translator.buildExprAssign(initctx, boundCount, index);
  658. }
  659. BuildCtx subctx(ctx);
  660. buildIterateLoop(subctx, true);
  661. if (!selectFirst)
  662. {
  663. OwnedHqlExpr test = createValue(no_eq, makeBoolType(), createValue(no_predec, LINK(boundCount.expr)), getZero());
  664. subctx.addFilter(test);
  665. }
  666. //Now we have the correct element, assign it to the pointer.
  667. //Need to be careful that the row we are pointing at is preserved, and doesn't go out of scope. (Don't need to worry about t can't be reused).
  668. BoundRow * curIter = translator.resolveSelectorDataset(subctx, selector);
  669. OwnedHqlExpr source = getPointer(curIter->queryBound());
  670. subctx.addAssign(rowExpr, source);
  671. subctx.addBreak();
  672. //Bind the expression as a row - so that the same select expression will get commoned up (e.g. sqagg)
  673. ctx.removeAssociation(savedMarker);
  674. return translator.bindRow(ctx, indexExpr, rowExpr);
  675. }
  676. BoundRow * MultiLevelDatasetCursor::doBuildIterateLoop(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * breakVar, bool topLevel)
  677. {
  678. IHqlExpression * root = queryRoot(expr);
  679. if (root)
  680. {
  681. if (isMultiLevelDatasetSelector(root, false))
  682. doBuildIterateLoop(ctx, root->queryChild(0), breakVar, false);
  683. }
  684. BuildCtx oldctx(ctx);
  685. BoundRow * row;
  686. if (root)
  687. {
  688. OwnedHqlExpr thisLevel = replaceExpression(expr, root, root->queryNormalizedSelector());
  689. row = translator.buildDatasetIterate(ctx, thisLevel, breakVar != NULL);
  690. }
  691. else
  692. {
  693. //Unusual... Something like (no_select(no_select(somethingComplex))) Assert on topLevel to prevent recursive stack fault
  694. //(see dlingle4.xhql for an example)
  695. assertex(!topLevel);
  696. root = expr->queryChild(0);
  697. row = translator.buildDatasetIterate(ctx, expr, breakVar != NULL);
  698. }
  699. if (breakVar)
  700. {
  701. if (topLevel)
  702. {
  703. ctx.addAssign(breakVar, queryBoolExpr(true));
  704. ctx.setNextDestructor();
  705. ctx.addAssign(breakVar, queryBoolExpr(false));
  706. }
  707. if (isMultiLevelDatasetSelector(root, false))
  708. {
  709. oldctx.addFilter(breakVar);
  710. oldctx.addBreak();
  711. }
  712. }
  713. return row;
  714. }
  715. //---------------------------------------------------------------------------
  716. BaseSetCursor::BaseSetCursor(HqlCppTranslator & _translator, IHqlExpression * _expr) : translator(_translator)
  717. {
  718. expr.set(_expr);
  719. }
  720. ListSetCursor::ListSetCursor(HqlCppTranslator & _translator, IHqlExpression * _expr) : BaseSetCursor(_translator, _expr)
  721. {
  722. }
  723. void ListSetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  724. {
  725. tgt.expr.setown(getCountExpr());
  726. }
  727. void ListSetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  728. {
  729. tgt.expr.set(queryBoolExpr(expr->numChildren() != 0));
  730. }
  731. void ListSetCursor::buildIsAll(BuildCtx & ctx, CHqlBoundExpr & tgt)
  732. {
  733. tgt.expr.set(queryBoolExpr(false));
  734. }
  735. void ListSetCursor::buildIterateLoop(BuildCtx & ctx, CHqlBoundExpr & curBound, bool needToBreak)
  736. {
  737. if (expr->numChildren() == 0)
  738. {
  739. ctx.addFilter(queryBoolExpr(false));
  740. curBound.expr.setown(createNullExpr(expr->queryType()->queryChildType()));
  741. return;
  742. }
  743. if (!needToBreak && (expr->numChildren() == 1))
  744. {
  745. translator.buildExpr(ctx, expr->queryChild(0), curBound);
  746. return;
  747. }
  748. CHqlBoundExpr boundList;
  749. translator.buildSimpleExpr(ctx, expr, boundList);
  750. OwnedHqlExpr loopVar = ctx.getTempDeclare(unsignedType, NULL);
  751. OwnedHqlExpr loopTest = createValue(no_lt, makeBoolType(), LINK(loopVar), getCountExpr());
  752. OwnedHqlExpr inc = createValue(no_postinc, loopVar->getType(), LINK(loopVar));
  753. translator.buildAssignToTemp(ctx, loopVar, queryZero());
  754. ctx.addLoop(loopTest, inc, false);
  755. curBound.expr.setown(createValue(no_index, LINK(expr->queryType()->queryChildType()), LINK(boundList.expr), LINK(loopVar)));
  756. }
  757. void ListSetCursor::buildIterateClass(BuildCtx & ctx, CHqlBoundExpr & tgt)
  758. {
  759. CHqlBoundExpr boundList;
  760. translator.buildSimpleExpr(ctx, expr, boundList);
  761. UNIMPLEMENTED;
  762. ctx.addQuoted("create fixed iterate (bound.length, bound.getAddress()");
  763. }
  764. void ListSetCursor::gatherSelect(BuildCtx & ctx, IHqlExpression * indexExpr, CHqlBoundExpr & value, HqlExprAttr & cond)
  765. {
  766. if (expr->numChildren() == 0)
  767. {
  768. OwnedHqlExpr null = getOutOfRangeValue(indexExpr);
  769. translator.buildExpr(ctx, null, value);
  770. return;
  771. }
  772. IHqlExpression * index = indexExpr->queryChild(1);
  773. if (index->isConstant())
  774. {
  775. OwnedHqlExpr folded = foldHqlExpression(index);
  776. unsigned which = (unsigned)folded->queryValue()->getIntValue()-1;
  777. if (which < expr->numChildren())
  778. translator.buildExpr(ctx, expr->queryChild(which), value);
  779. else
  780. {
  781. OwnedHqlExpr null = getOutOfRangeValue(indexExpr);
  782. translator.buildExpr(ctx, null, value);
  783. }
  784. }
  785. else
  786. {
  787. CHqlBoundExpr boundList;
  788. translator.buildSimpleExpr(ctx, expr, boundList);
  789. CHqlBoundExpr boundIndex;
  790. ITypeInfo * elementType = expr->queryType()->queryChildType(); // not indexExpr->getType() because may now be more specific
  791. OwnedHqlExpr base0Index = adjustIndexBaseToZero(index);
  792. if (indexExpr->hasProperty(noBoundCheckAtom))
  793. translator.buildExpr(ctx, base0Index, boundIndex);
  794. else
  795. translator.buildSimpleExpr(ctx, base0Index, boundIndex);
  796. value.expr.setown(createValue(no_index, LINK(elementType), LINK(boundList.expr), LINK(boundIndex.expr)));
  797. if (!indexExpr->hasProperty(noBoundCheckAtom))
  798. {
  799. ITypeInfo * indexType = boundIndex.expr->queryType();
  800. //ok to subtract early and remove a check for > 0 on unsigned values because they will wrap and fail upper limit test
  801. if (indexType->isSigned())
  802. cond.setown(createBoolExpr(no_ge, LINK(boundIndex.expr), getZero()));
  803. if (indexType->getCardinality() > expr->numChildren())
  804. extendConditionOwn(cond, no_and, createBoolExpr(no_lt, LINK(boundIndex.expr), getCountExpr()));
  805. }
  806. }
  807. }
  808. void ListSetCursor::buildExprSelect(BuildCtx & ctx, IHqlExpression * indexExpr, CHqlBoundExpr & tgt)
  809. {
  810. CHqlBoundExpr value;
  811. HqlExprAttr cond;
  812. gatherSelect(ctx, indexExpr, value, cond);
  813. if (cond)
  814. {
  815. translator.buildTempExpr(ctx, indexExpr, tgt);
  816. return;
  817. CHqlBoundTarget tempTarget;
  818. translator.createTempFor(ctx, indexExpr, tempTarget);
  819. buildAssignSelect(ctx, tempTarget, indexExpr);
  820. tgt.setFromTarget(tempTarget);
  821. }
  822. else
  823. tgt.set(value);
  824. }
  825. void ListSetCursor::buildAssignSelect(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * indexExpr)
  826. {
  827. CHqlBoundExpr value;
  828. HqlExprAttr cond;
  829. gatherSelect(ctx, indexExpr, value, cond);
  830. if (cond)
  831. {
  832. BuildCtx subctx(ctx);
  833. IHqlStmt * e = subctx.addFilter(cond);
  834. translator.assign(subctx, target, value);
  835. subctx.selectElse(e);
  836. OwnedHqlExpr null = getOutOfRangeValue(indexExpr);
  837. translator.buildExprAssign(subctx, target, null);
  838. }
  839. else
  840. translator.assign(ctx, target, value);
  841. }
  842. IHqlExpression * ListSetCursor::getCountExpr()
  843. {
  844. return getSizetConstant(expr->numChildren());
  845. }
  846. //---------------------------------------------------------------------------
  847. AllSetCursor::AllSetCursor(HqlCppTranslator & _translator) : BaseSetCursor(_translator, NULL)
  848. {
  849. }
  850. void AllSetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  851. {
  852. translator.throwError(HQLERR_CountAllSet);
  853. }
  854. void AllSetCursor::buildIsAll(BuildCtx & ctx, CHqlBoundExpr & tgt)
  855. {
  856. tgt.expr.set(queryBoolExpr(true));
  857. }
  858. void AllSetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  859. {
  860. tgt.expr.set(queryBoolExpr(true));
  861. }
  862. void AllSetCursor::buildIterateLoop(BuildCtx & ctx, CHqlBoundExpr & curBound, bool needToBreak)
  863. {
  864. translator.throwError(HQLERR_IndexAllSet);
  865. }
  866. void AllSetCursor::buildIterateClass(BuildCtx & ctx, CHqlBoundExpr & tgt)
  867. {
  868. translator.throwError(HQLERR_IndexAllSet);
  869. }
  870. void AllSetCursor::buildExprSelect(BuildCtx & ctx, IHqlExpression * indexExpr, CHqlBoundExpr & tgt)
  871. {
  872. translator.throwError(HQLERR_IndexAllSet);
  873. }
  874. void AllSetCursor::buildAssignSelect(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * indexExpr)
  875. {
  876. translator.throwError(HQLERR_IndexAllSet);
  877. }
  878. //---------------------------------------------------------------------------
  879. GeneralSetCursor::GeneralSetCursor(HqlCppTranslator & _translator, IHqlExpression * _expr, CHqlBoundExpr & boundSet) : BaseSetCursor(_translator, _expr)
  880. {
  881. isAll.setown(boundSet.getIsAll());
  882. ITypeInfo * elementType = LINK(expr->queryType()->queryChildType());
  883. if (!elementType)
  884. elementType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  885. element.setown(createField(valueAtom, elementType, NULL));
  886. HqlExprArray fields;
  887. fields.append(*LINK(element));
  888. ds.setown(createDataset(no_anon, createRecord(fields), LINK(expr)));
  889. dsCursor.setown(new InlineBlockDatasetCursor(translator, ds, boundSet));
  890. }
  891. void GeneralSetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  892. {
  893. checkNotAll(ctx);
  894. dsCursor->buildCount(ctx, tgt);
  895. }
  896. void GeneralSetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  897. {
  898. if (isAll->queryValue())
  899. {
  900. if (isAll->queryValue()->getBoolValue())
  901. {
  902. tgt.expr.set(queryBoolExpr(true));
  903. return;
  904. }
  905. dsCursor->buildExists(ctx, tgt);
  906. }
  907. else
  908. {
  909. dsCursor->buildExists(ctx, tgt);
  910. tgt.expr.setown(createBoolExpr(no_or, LINK(isAll), LINK(tgt.expr)));
  911. }
  912. }
  913. void GeneralSetCursor::buildIsAll(BuildCtx & ctx, CHqlBoundExpr & tgt)
  914. {
  915. tgt.expr.set(isAll);
  916. }
  917. void GeneralSetCursor::buildIterateLoop(BuildCtx & ctx, CHqlBoundExpr & curBound, bool needToBreak)
  918. {
  919. BoundRow * cursor = dsCursor->buildIterateLoop(ctx, needToBreak);
  920. OwnedHqlExpr select = createSelectExpr(LINK(cursor->querySelector()), LINK(element));
  921. translator.buildExpr(ctx, select, curBound);
  922. }
  923. void GeneralSetCursor::buildIterateClass(BuildCtx & ctx, CHqlBoundExpr & tgt)
  924. {
  925. UNIMPLEMENTED;
  926. HqlExprAttr row;
  927. dsCursor->buildIterateClass(ctx, tgt.expr, row);
  928. }
  929. IHqlExpression * GeneralSetCursor::createDatasetSelect(IHqlExpression * indexExpr)
  930. {
  931. HqlExprArray args;
  932. args.append(*LINK(ds));
  933. unwindChildren(args, indexExpr, 1);
  934. return createRow(no_selectnth, args);
  935. }
  936. void GeneralSetCursor::buildExprSelect(BuildCtx & ctx, IHqlExpression * indexExpr, CHqlBoundExpr & tgt)
  937. {
  938. if (indexExpr->hasProperty(noBoundCheckAtom))
  939. {
  940. if (indexExpr->hasProperty(forceAllCheckAtom))
  941. checkNotAll(ctx);
  942. OwnedHqlExpr dsIndexExpr = createDatasetSelect(indexExpr);
  943. BoundRow * cursor = dsCursor->buildSelectNth(ctx, dsIndexExpr);
  944. OwnedHqlExpr select = createSelectExpr(LINK(dsIndexExpr), LINK(element));
  945. translator.buildExpr(ctx, select, tgt);
  946. }
  947. else
  948. {
  949. translator.buildTempExpr(ctx, indexExpr, tgt);
  950. }
  951. }
  952. void GeneralSetCursor::buildAssignSelect(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * indexExpr)
  953. {
  954. if (!indexExpr->hasProperty(noBoundCheckAtom) || indexExpr->hasProperty(forceAllCheckAtom))
  955. checkNotAll(ctx);
  956. OwnedHqlExpr dsIndexExpr = createDatasetSelect(indexExpr);
  957. BoundRow * cursor = dsCursor->buildSelectNth(ctx, dsIndexExpr);
  958. if (cursor)
  959. {
  960. OwnedHqlExpr select = createSelectExpr(LINK(dsIndexExpr), LINK(element));
  961. if (!cursor->isConditional())
  962. translator.buildExprAssign(ctx, target, select);
  963. else
  964. {
  965. // if (row) tgt = x else tgt = dft;
  966. BuildCtx subctx(ctx);
  967. IHqlStmt * e = subctx.addFilter(cursor->queryBound());
  968. cursor->setConditional(false); // yuk!
  969. translator.buildExprAssign(subctx, target, select);
  970. cursor->setConditional(true);
  971. subctx.selectElse(e);
  972. OwnedHqlExpr null = getOutOfRangeValue(indexExpr);
  973. translator.buildExprAssign(subctx, target, null);
  974. }
  975. }
  976. else
  977. {
  978. OwnedHqlExpr null = getOutOfRangeValue(indexExpr);
  979. translator.buildExprAssign(ctx, target, null);
  980. }
  981. }
  982. void GeneralSetCursor::checkNotAll(BuildCtx & ctx)
  983. {
  984. if (isAll->queryValue())
  985. {
  986. if (isAll->queryValue()->getBoolValue())
  987. translator.throwError(HQLERR_IndexAllSet);
  988. }
  989. else
  990. {
  991. //MORE: Should only really do this once...
  992. BuildCtx subctx(ctx);
  993. subctx.addFilter(isAll);
  994. IHqlExpression * msg = translator.createFailMessage("Cannot index ALL", NULL, NULL, translator.queryCurrentActivityId(ctx));
  995. OwnedHqlExpr fail = createValue(no_fail, makeVoidType(), getZero(), msg, getDefaultAttr());
  996. translator.buildStmt(subctx, fail);
  997. }
  998. }
  999. bool GeneralSetCursor::isSingleValued()
  1000. {
  1001. if (!matchesBoolean(isAll, false))
  1002. return false;
  1003. // return dsCursor->hasSingleRow();
  1004. return false;
  1005. }
  1006. //---------------------------------------------------------------------------
  1007. CreateSetCursor::CreateSetCursor(HqlCppTranslator & _translator, IHqlExpression * _expr, IHqlCppDatasetCursor * _dsCursor) : BaseSetCursor(_translator, _expr)
  1008. {
  1009. ds.set(expr->queryChild(0));
  1010. value.set(expr->queryChild(1));
  1011. dsCursor.set(_dsCursor);
  1012. }
  1013. void CreateSetCursor::buildCount(BuildCtx & ctx, CHqlBoundExpr & tgt)
  1014. {
  1015. dsCursor->buildCount(ctx, tgt);
  1016. }
  1017. void CreateSetCursor::buildExists(BuildCtx & ctx, CHqlBoundExpr & tgt)
  1018. {
  1019. dsCursor->buildExists(ctx, tgt);
  1020. }
  1021. void CreateSetCursor::buildIsAll(BuildCtx & ctx, CHqlBoundExpr & tgt)
  1022. {
  1023. tgt.expr.set(queryBoolExpr(false));
  1024. }
  1025. void CreateSetCursor::buildIterateLoop(BuildCtx & ctx, CHqlBoundExpr & curBound, bool needToBreak)
  1026. {
  1027. BoundRow * cursor = dsCursor->buildIterateLoop(ctx, needToBreak);
  1028. translator.buildExpr(ctx, value, curBound);
  1029. }
  1030. void CreateSetCursor::buildIterateClass(BuildCtx & ctx, CHqlBoundExpr & tgt)
  1031. {
  1032. UNIMPLEMENTED;
  1033. }
  1034. IHqlExpression * CreateSetCursor::createDatasetSelect(IHqlExpression * indexExpr)
  1035. {
  1036. if (value->getOperator() == no_select &&
  1037. (value->queryChild(0)->queryNormalizedSelector() == ds->queryNormalizedSelector()))
  1038. {
  1039. HqlExprArray args;
  1040. args.append(*LINK(ds));
  1041. unwindChildren(args, indexExpr, 1);
  1042. IHqlExpression * select = createRow(no_selectnth, args);
  1043. return createNewSelectExpr(select, LINK(value->queryChild(1)));
  1044. }
  1045. else
  1046. {
  1047. OwnedHqlExpr field = createField(createIdentifierAtom("__f1__"), value->getType(), NULL);
  1048. IHqlExpression * aggregateRecord = createRecord(field);
  1049. IHqlExpression * assign = createAssign(createSelectExpr(getSelf(aggregateRecord), LINK(field)), LINK(value));
  1050. IHqlExpression * transform = createValue(no_newtransform, makeTransformType(aggregateRecord->getType()), assign);
  1051. HqlExprArray args;
  1052. args.append(*createDataset(no_newusertable, LINK(ds), createComma(aggregateRecord, transform)));
  1053. unwindChildren(args, indexExpr, 1);
  1054. IHqlExpression * select = createRow(no_selectnth, args);
  1055. return createNewSelectExpr(select, LINK(field));
  1056. }
  1057. }
  1058. void CreateSetCursor::buildExprSelect(BuildCtx & ctx, IHqlExpression * indexExpr, CHqlBoundExpr & tgt)
  1059. {
  1060. OwnedHqlExpr newExpr = createDatasetSelect(indexExpr);
  1061. translator.buildExpr(ctx, newExpr, tgt);
  1062. }
  1063. void CreateSetCursor::buildAssignSelect(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * indexExpr)
  1064. {
  1065. OwnedHqlExpr newExpr = createDatasetSelect(indexExpr);
  1066. translator.buildExprAssign(ctx, target, newExpr);
  1067. }
  1068. bool CreateSetCursor::isSingleValued()
  1069. {
  1070. return hasSingleRow(ds);
  1071. }
  1072. //---------------------------------------------------------------------------
  1073. IHqlCppSetCursor * HqlCppTranslator::createSetSelector(BuildCtx & ctx, IHqlExpression * expr)
  1074. {
  1075. OwnedHqlExpr normalized = normalizeListCasts(expr);
  1076. switch (normalized->getOperator())
  1077. {
  1078. case no_alias_scope:
  1079. {
  1080. unsigned max = normalized->numChildren();
  1081. for (unsigned idx = 1; idx < max; idx++)
  1082. expandAliases(ctx, normalized->queryChild(idx));
  1083. return createSetSelector(ctx, normalized->queryChild(0));
  1084. }
  1085. case no_null:
  1086. return new ListSetCursor(*this, normalized);
  1087. case no_all:
  1088. return new AllSetCursor(*this);
  1089. case no_list:
  1090. if ((normalized->numChildren() == 0) || (normalized->queryType()->queryChildType()->getSize() != UNKNOWN_LENGTH))
  1091. return new ListSetCursor(*this, normalized);
  1092. break; // default
  1093. case no_createset:
  1094. {
  1095. Owned<IHqlCppDatasetCursor> dsCursor = createDatasetSelector(ctx, expr->queryChild(0));
  1096. return new CreateSetCursor(*this, expr, dsCursor);
  1097. }
  1098. }
  1099. CHqlBoundExpr bound;
  1100. buildSimpleExpr(ctx, normalized, bound);
  1101. return new GeneralSetCursor(*this, normalized, bound);
  1102. }
  1103. //---------------------------------------------------------------------------
  1104. IHqlCppDatasetCursor * HqlCppTranslator::createDatasetSelector(BuildCtx & ctx, IHqlExpression * expr)
  1105. {
  1106. // OwnedHqlExpr normalized = normalizeDatasetCasts(expr);
  1107. switch (expr->getOperator())
  1108. {
  1109. case no_null:
  1110. break;
  1111. case no_select:
  1112. if (isMultiLevelDatasetSelector(expr, false))
  1113. return new MultiLevelDatasetCursor(*this, expr);
  1114. break;
  1115. }
  1116. CHqlBoundExpr bound;
  1117. buildDataset(ctx, expr, bound, FormatNatural);
  1118. if (bound.expr->isDatarow() || !isArrayRowset(bound.expr->queryType()))
  1119. return new InlineBlockDatasetCursor(*this, expr, bound);
  1120. else if (bound.expr->isDictionary())
  1121. return new InlineLinkedDictionaryCursor(*this, expr, bound);
  1122. else
  1123. return new InlineLinkedDatasetCursor(*this, expr, bound);
  1124. }
  1125. //---------------------------------------------------------------------------
  1126. CHqlCppDatasetBuilder::CHqlCppDatasetBuilder(HqlCppTranslator & _translator, IHqlExpression * _record)
  1127. : translator(_translator), record(_record)
  1128. {
  1129. }
  1130. DatasetBuilderBase::DatasetBuilderBase(HqlCppTranslator & _translator, IHqlExpression * _record, bool _buildLinkedRows) : CHqlCppDatasetBuilder(_translator, _record)
  1131. {
  1132. StringBuffer rowName;
  1133. unique_id_t id = translator.getUniqueId();
  1134. appendUniqueId(instanceName.append("cr"), id);
  1135. builderName.append(instanceName).append(".rowBuilder()");
  1136. rowName.append(instanceName).append(".rowBuilder().row()"); // more!
  1137. IHqlExpression * linkAttr = _buildLinkedRows ? getLinkCountedAttr() : NULL;
  1138. ITypeInfo * rowType = makeRowReferenceType(record);
  1139. if (_buildLinkedRows)
  1140. rowType = makeAttributeModifier(rowType, getLinkCountedAttr());
  1141. OwnedHqlExpr cursorVar = createVariable(rowName.str(), rowType);
  1142. dataset.setown(createDataset(no_anon, LINK(record), createComma(getSelfAttr(), linkAttr)));
  1143. }
  1144. BoundRow * DatasetBuilderBase::buildCreateRow(BuildCtx & ctx)
  1145. {
  1146. StringBuffer s;
  1147. OwnedHqlExpr cond = createQuoted(s.append(instanceName).append(".createRow()"), makeBoolType());
  1148. if (isRestricted())
  1149. ctx.addFilter(cond);
  1150. else
  1151. ctx.addExpr(cond);
  1152. return translator.bindSelf(ctx, dataset, builderName);
  1153. }
  1154. BoundRow * DatasetBuilderBase::buildDeserializeRow(BuildCtx & ctx, IHqlExpression * serializedInput)
  1155. {
  1156. StringBuffer serializerInstanceName;
  1157. translator.ensureRowSerializer(serializerInstanceName, ctx, record, deserializerAtom);
  1158. StringBuffer s;
  1159. s.append(instanceName).append(".deserializeRow(*");
  1160. s.append(serializerInstanceName).append(", ");
  1161. translator.generateExprCpp(s, serializedInput).append(");");
  1162. ctx.addQuoted(s);
  1163. return translator.bindSelf(ctx, dataset, builderName);
  1164. }
  1165. void DatasetBuilderBase::finishRow(BuildCtx & ctx, BoundRow * selfCursor)
  1166. {
  1167. OwnedHqlExpr size = createSizeof(selfCursor->querySelector());
  1168. doFinishRow(ctx, selfCursor, size);
  1169. }
  1170. void DatasetBuilderBase::doFinishRow(BuildCtx & ctx, BoundRow * selfCursor, IHqlExpression *size)
  1171. {
  1172. CHqlBoundExpr boundSize;
  1173. translator.buildExpr(ctx, size, boundSize);
  1174. StringBuffer s;
  1175. s.append(instanceName).append(".finalizeRow(");
  1176. translator.generateExprCpp(s, boundSize.expr).append(");");
  1177. ctx.addQuoted(s);
  1178. ctx.removeAssociation(selfCursor);
  1179. }
  1180. //---------------------------------------------------------------------------
  1181. BlockedDatasetBuilder::BlockedDatasetBuilder(HqlCppTranslator & _translator, IHqlExpression * _record) : DatasetBuilderBase(_translator, _record, false)
  1182. {
  1183. forceLength = false;
  1184. }
  1185. void BlockedDatasetBuilder::buildDeclare(BuildCtx & ctx)
  1186. {
  1187. StringBuffer decl, extra;
  1188. if (count)
  1189. {
  1190. CHqlBoundExpr boundCount;
  1191. translator.buildExpr(ctx, count, boundCount);
  1192. if (translator.isFixedRecordSize(record))
  1193. {
  1194. //RtlFixedDatasetCreator cursor(len, data, size)
  1195. decl.append("RtlLimitedFixedDatasetBuilder");
  1196. extra.append(translator.getFixedRecordSize(record));
  1197. }
  1198. else
  1199. {
  1200. //RtlVariableDatasetCursor cursor(len, data, recordSize)
  1201. decl.append("RtlLimitedVariableDatasetBuilder");
  1202. translator.buildMetaForRecord(extra, record);
  1203. }
  1204. translator.ensureContextAvailable(ctx);
  1205. decl.append(" ").append(instanceName).append("(").append(extra).append(",");
  1206. translator.generateExprCpp(decl, boundCount.expr).append(",");
  1207. if (forceLength)
  1208. {
  1209. OwnedHqlExpr clearFunc = translator.getClearRecordFunction(record);
  1210. translator.generateExprCpp(decl, clearFunc).append(", ctx);");
  1211. }
  1212. else
  1213. decl.append("NULL,NULL);");
  1214. }
  1215. else
  1216. {
  1217. if (translator.isFixedRecordSize(record))
  1218. {
  1219. //RtlFixedDatasetCreator cursor(len, data, size)
  1220. decl.append("RtlFixedDatasetBuilder");
  1221. extra.append(translator.getFixedRecordSize(record)).append(", 0");
  1222. }
  1223. else
  1224. {
  1225. //RtlVariableDatasetCursor cursor(len, data, recordSize)
  1226. decl.append("RtlVariableDatasetBuilder");
  1227. translator.buildMetaForRecord(extra, record);
  1228. }
  1229. decl.append(" ").append(instanceName).append("(").append(extra).append(");");
  1230. }
  1231. ctx.addQuoted(decl);
  1232. }
  1233. void BlockedDatasetBuilder::buildFinish(BuildCtx & ctx, const CHqlBoundTarget & target)
  1234. {
  1235. //more: should I do this by really calling a function?
  1236. StringBuffer s;
  1237. s.append(instanceName).append(".getData(");
  1238. translator.generateExprCpp(s, target.length);
  1239. s.append(",");
  1240. OwnedHqlExpr ref = createValue(no_reference, target.getType(), LINK(target.expr));
  1241. translator.generateExprCpp(s, ref);
  1242. s.append(");");
  1243. ctx.addQuoted(s);
  1244. }
  1245. void BlockedDatasetBuilder::buildFinish(BuildCtx & ctx, CHqlBoundExpr & bound)
  1246. {
  1247. StringBuffer s;
  1248. s.clear().append(instanceName).append(".getSize()");
  1249. bound.length.setown(createQuoted(s.str(), LINK(unsignedType)));
  1250. s.clear().append(instanceName).append(".queryData()");
  1251. bound.expr.setown(createQuoted(s.str(), makeReferenceModifier(dataset->getType())));
  1252. }
  1253. //---------------------------------------------------------------------------
  1254. SingleRowTempDatasetBuilder::SingleRowTempDatasetBuilder(HqlCppTranslator & _translator, IHqlExpression * _record, BoundRow * _row) : CHqlCppDatasetBuilder(_translator, _record)
  1255. {
  1256. row.set(_row);
  1257. cursor.set(row);
  1258. }
  1259. void SingleRowTempDatasetBuilder::buildDeclare(BuildCtx & ctx)
  1260. {
  1261. }
  1262. BoundRow * SingleRowTempDatasetBuilder::buildCreateRow(BuildCtx & ctx)
  1263. {
  1264. cursor.set(row);
  1265. return row;
  1266. }
  1267. void SingleRowTempDatasetBuilder::buildFinish(BuildCtx & ctx, const CHqlBoundTarget & target)
  1268. {
  1269. assertex(cursor != NULL);
  1270. }
  1271. void SingleRowTempDatasetBuilder::buildFinish(BuildCtx & ctx, CHqlBoundExpr & target)
  1272. {
  1273. assertex(cursor != NULL);
  1274. }
  1275. void SingleRowTempDatasetBuilder::finishRow(BuildCtx & ctx, BoundRow * selfCursor)
  1276. {
  1277. }
  1278. //---------------------------------------------------------------------------
  1279. InlineDatasetBuilder::InlineDatasetBuilder(HqlCppTranslator & _translator, IHqlExpression * _record, IHqlExpression * _size, IHqlExpression * _address) : CHqlCppDatasetBuilder(_translator, _record)
  1280. {
  1281. StringBuffer cursorName;
  1282. getUniqueId(cursorName.append("p"));
  1283. ITypeInfo * rowType = makeRowReferenceType(record);
  1284. cursorVar.setown(createVariable(cursorName.str(), rowType));
  1285. dataset.setown(createDataset(no_anon, LINK(record), getSelfAttr()));
  1286. size.set(_size);
  1287. address.set(_address);
  1288. }
  1289. void InlineDatasetBuilder::buildDeclare(BuildCtx & ctx)
  1290. {
  1291. //NB: This is only ever used where the target has already been checked to ensure there is enough room
  1292. //If we wanted to be clever we would need to use a RtlNestedRowBuilder(parent, <start-of-this-row>, ...);
  1293. ctx.addDeclare(cursorVar, address);
  1294. }
  1295. BoundRow * InlineDatasetBuilder::buildCreateRow(BuildCtx & ctx)
  1296. {
  1297. Owned<BoundRow> cursor = translator.createTableCursor(dataset, cursorVar, no_self, NULL);
  1298. ctx.associate(*cursor);
  1299. return cursor;
  1300. }
  1301. void InlineDatasetBuilder::buildFinish(BuildCtx & ctx, const CHqlBoundTarget & target)
  1302. {
  1303. ctx.addAssign(target.length, size);
  1304. }
  1305. void InlineDatasetBuilder::buildFinish(BuildCtx & ctx, CHqlBoundExpr & bound)
  1306. {
  1307. bound.length.set(size);
  1308. bound.expr.set(address);
  1309. }
  1310. void InlineDatasetBuilder::finishRow(BuildCtx & ctx, BoundRow * selfCursor)
  1311. {
  1312. CHqlBoundExpr bound;
  1313. translator.getRecordSize(ctx, selfCursor->querySelector(), bound);
  1314. if (translator.queryOptions().optimizeIncrement)
  1315. {
  1316. ctx.addAssignIncrement(selfCursor->queryBound(), bound.expr);
  1317. }
  1318. else
  1319. {
  1320. OwnedHqlExpr inc = createValue(no_add, LINK(selfCursor->queryBound()), LINK(bound.expr));
  1321. ctx.addAssign(selfCursor->queryBound(), inc);
  1322. }
  1323. }
  1324. //---------------------------------------------------------------------------
  1325. LinkedDatasetBuilderBase::LinkedDatasetBuilderBase(HqlCppTranslator & _translator, IHqlExpression * _record) : DatasetBuilderBase(_translator, _record, true)
  1326. {
  1327. }
  1328. void LinkedDatasetBuilderBase::finishRow(BuildCtx & ctx, BoundRow * selfCursor)
  1329. {
  1330. OwnedHqlExpr size = translator.getRecordSize(selfCursor->querySelector());
  1331. doFinishRow(ctx, selfCursor, size);
  1332. }
  1333. void LinkedDatasetBuilderBase::buildFinish(BuildCtx & ctx, const CHqlBoundTarget & target)
  1334. {
  1335. //more: should I do this by really calling a function?
  1336. StringBuffer s;
  1337. s.append(instanceName).append(".getcount()");
  1338. if (hasWrapperModifier(target.queryType()))
  1339. {
  1340. translator.generateExprCpp(s.clear(), target.expr);
  1341. s.append(".setown(").append(instanceName).append(".getcount()");
  1342. s.append(",").append(instanceName).append(".linkrows());");
  1343. ctx.addQuoted(s);
  1344. }
  1345. else
  1346. {
  1347. OwnedHqlExpr countExpr = createQuoted(s.str(), LINK(unsignedType));
  1348. ctx.addAssign(target.count, countExpr);
  1349. s.clear().append(instanceName).append(".linkrows()");
  1350. OwnedHqlExpr rowsExpr = createQuoted(s.str(), dataset->getType());
  1351. ctx.addAssign(target.expr, rowsExpr);
  1352. }
  1353. }
  1354. void LinkedDatasetBuilderBase::buildFinish(BuildCtx & ctx, CHqlBoundExpr & bound)
  1355. {
  1356. StringBuffer s;
  1357. s.clear().append(instanceName).append(".getcount()");
  1358. bound.count.setown(createQuoted(s.str(), LINK(unsignedType)));
  1359. s.clear().append(instanceName).append(".queryrows()");
  1360. bound.expr.setown(createQuoted(s.str(), makeReferenceModifier(dataset->getType())));
  1361. }
  1362. bool LinkedDatasetBuilderBase::buildLinkRow(BuildCtx & ctx, BoundRow * sourceRow)
  1363. {
  1364. IHqlExpression * sourceRecord = sourceRow->queryRecord();
  1365. if (recordTypesMatch(sourceRecord, record) && sourceRow->isBinary())
  1366. {
  1367. OwnedHqlExpr source = getPointer(sourceRow->queryBound());
  1368. BuildCtx subctx(ctx);
  1369. if (sourceRow->isConditional())
  1370. subctx.addFilter(source);
  1371. if (sourceRow->isLinkCounted())
  1372. {
  1373. StringBuffer s;
  1374. s.append(instanceName).append(".append(");
  1375. translator.generateExprCpp(s, source);
  1376. s.append(");");
  1377. subctx.addQuoted(s);
  1378. return true;
  1379. }
  1380. IHqlExpression * sourceExpr = sourceRow->querySelector();
  1381. OwnedHqlExpr rowExpr = sourceExpr->isDataset() ? ensureActiveRow(sourceExpr) : LINK(sourceExpr);
  1382. OwnedHqlExpr size = createSizeof(rowExpr);
  1383. CHqlBoundExpr boundSize;
  1384. translator.buildExpr(ctx, size, boundSize);
  1385. StringBuffer s;
  1386. s.append(instanceName).append(".cloneRow(");
  1387. translator.generateExprCpp(s, boundSize.expr).append(",");
  1388. translator.generateExprCpp(s, source);
  1389. s.append(");");
  1390. subctx.addQuoted(s);
  1391. return true;
  1392. }
  1393. return false;
  1394. }
  1395. bool LinkedDatasetBuilderBase::buildAppendRows(BuildCtx & ctx, IHqlExpression * expr)
  1396. {
  1397. IHqlExpression * sourceRecord = expr->queryRecord();
  1398. if (recordTypesMatch(sourceRecord, record))
  1399. {
  1400. CHqlBoundExpr bound;
  1401. if (!ctx.getMatchExpr(expr, bound))
  1402. {
  1403. bool tryToOptimize = false;
  1404. switch (expr->getOperator())
  1405. {
  1406. case no_select:
  1407. if (isMultiLevelDatasetSelector(expr, false))
  1408. break;
  1409. if (!hasLinkedRow(expr->queryType()))
  1410. break;
  1411. tryToOptimize = true;
  1412. break;
  1413. default:
  1414. //Don't speculatively evaluate if the expression isn't pure
  1415. tryToOptimize = alwaysEvaluatesToBound(expr) && expr->isPure();
  1416. break;
  1417. }
  1418. if (tryToOptimize)
  1419. translator.buildDataset(ctx, expr, bound, FormatNatural);
  1420. }
  1421. if (bound.expr)
  1422. {
  1423. if (hasLinkedRow(bound.queryType()))
  1424. {
  1425. OwnedHqlExpr source = getPointer(bound.expr);
  1426. StringBuffer s;
  1427. s.append(instanceName).append(".appendRows(");
  1428. translator.generateExprCpp(s, bound.count);
  1429. s.append(",");
  1430. translator.generateExprCpp(s, source);
  1431. s.append(");");
  1432. ctx.addQuoted(s);
  1433. return true;
  1434. }
  1435. }
  1436. }
  1437. return false;
  1438. }
  1439. LinkedDatasetBuilder::LinkedDatasetBuilder(HqlCppTranslator & _translator, IHqlExpression * _record, IHqlExpression * _choosenLimit) : LinkedDatasetBuilderBase(_translator, _record)
  1440. {
  1441. choosenLimit.set(_choosenLimit);
  1442. }
  1443. void LinkedDatasetBuilder::buildDeclare(BuildCtx & ctx)
  1444. {
  1445. StringBuffer decl, allocatorName;
  1446. OwnedHqlExpr curActivityId = translator.getCurrentActivityId(ctx);
  1447. translator.ensureRowAllocator(allocatorName, ctx, record, curActivityId);
  1448. decl.append("RtlLinkedDatasetBuilder ").append(instanceName).append("(");
  1449. decl.append(allocatorName);
  1450. if (choosenLimit)
  1451. {
  1452. CHqlBoundExpr boundLimit;
  1453. translator.buildExpr(ctx, choosenLimit, boundLimit);
  1454. translator.generateExprCpp(decl.append(", "), boundLimit.expr);
  1455. }
  1456. decl.append(");");
  1457. ctx.addQuoted(decl);
  1458. }
  1459. LinkedDictionaryBuilder::LinkedDictionaryBuilder(HqlCppTranslator & _translator, IHqlExpression * _record) : LinkedDatasetBuilderBase(_translator, _record)
  1460. {
  1461. }
  1462. void LinkedDictionaryBuilder::buildDeclare(BuildCtx & ctx)
  1463. {
  1464. StringBuffer decl, allocatorName;
  1465. OwnedHqlExpr curActivityId = translator.getCurrentActivityId(ctx);
  1466. translator.ensureRowAllocator(allocatorName, ctx, record, curActivityId);
  1467. StringBuffer lookupHelperName;
  1468. OwnedHqlExpr dict = createDictionary(no_null, record.getLink()); // MORE - is the actual dict not available?
  1469. translator.buildDictionaryHashClass(ctx, record, dict, lookupHelperName);
  1470. decl.append("RtlLinkedDictionaryBuilder ").append(instanceName).append("(");
  1471. decl.append(allocatorName).append(", &").append(lookupHelperName);
  1472. decl.append(");");
  1473. ctx.addQuoted(decl);
  1474. }
  1475. //---------------------------------------------------------------------------
  1476. SetBuilder::SetBuilder(HqlCppTranslator & _translator, ITypeInfo * fieldType, IHqlExpression * _allVar) : translator(_translator)
  1477. {
  1478. HqlExprArray fields;
  1479. fields.append(*createField(valueAtom, LINK(fieldType), NULL));
  1480. record.setown(createRecord(fields));
  1481. allVar.set(_allVar);
  1482. activeRow = NULL;
  1483. }
  1484. void SetBuilder::buildDeclare(BuildCtx & ctx)
  1485. {
  1486. datasetBuilder->buildDeclare(ctx);
  1487. }
  1488. IReferenceSelector * SetBuilder::buildCreateElement(BuildCtx & ctx)
  1489. {
  1490. activeRow = datasetBuilder->buildCreateRow(ctx);
  1491. OwnedHqlExpr select = createSelectExpr(LINK(activeRow->querySelector()), LINK(record->queryChild(0)));
  1492. return translator.buildReference(ctx, select);
  1493. }
  1494. void SetBuilder::buildFinish(BuildCtx & ctx, const CHqlBoundTarget & target)
  1495. {
  1496. if (target.isAll && (allVar != target.isAll))
  1497. {
  1498. assertex(allVar != NULL);
  1499. ctx.addAssign(target.isAll, allVar);
  1500. }
  1501. datasetBuilder->buildFinish(ctx, target);
  1502. }
  1503. void SetBuilder::finishElement(BuildCtx & ctx)
  1504. {
  1505. datasetBuilder->finishRow(ctx, activeRow);
  1506. activeRow = NULL;
  1507. }
  1508. void SetBuilder::setAll(BuildCtx & ctx, IHqlExpression * isAll)
  1509. {
  1510. if (allVar)
  1511. {
  1512. CHqlBoundExpr bound;
  1513. translator.buildExpr(ctx, isAll, bound);
  1514. ctx.addAssign(allVar, bound.expr);
  1515. }
  1516. else
  1517. {
  1518. if (!matchesBoolean(isAll, false))
  1519. throwUnexpected();
  1520. }
  1521. }
  1522. TempSetBuilder::TempSetBuilder(HqlCppTranslator & _translator, ITypeInfo * fieldType, IHqlExpression * _allVar) : SetBuilder(_translator, fieldType, _allVar)
  1523. {
  1524. datasetBuilder.setown(new BlockedDatasetBuilder(translator, record));
  1525. }
  1526. InlineSetBuilder::InlineSetBuilder(HqlCppTranslator & _translator, ITypeInfo * fieldType, IHqlExpression * _allVar, IHqlExpression * _size, IHqlExpression * _address) : SetBuilder(_translator, fieldType, _allVar)
  1527. {
  1528. datasetBuilder.setown(new InlineDatasetBuilder(translator, record, _size, _address));
  1529. }
  1530. IHqlCppSetBuilder * HqlCppTranslator::createTempSetBuilder(ITypeInfo * type, IHqlExpression * allVar)
  1531. {
  1532. return new TempSetBuilder(*this, type, allVar);
  1533. }
  1534. IHqlCppSetBuilder * HqlCppTranslator::createInlineSetBuilder(ITypeInfo * type, IHqlExpression * allVar, IHqlExpression * size, IHqlExpression * address)
  1535. {
  1536. assertex(allVar);
  1537. return new InlineSetBuilder(*this, type, allVar, size, address);
  1538. }
  1539. IHqlCppDatasetBuilder * HqlCppTranslator::createBlockedDatasetBuilder(IHqlExpression * record)
  1540. {
  1541. return new BlockedDatasetBuilder(*this, record);
  1542. }
  1543. IHqlCppDatasetBuilder * HqlCppTranslator::createLinkedDatasetBuilder(IHqlExpression * record, IHqlExpression * choosenLimit)
  1544. {
  1545. return new LinkedDatasetBuilder(*this, record, choosenLimit);
  1546. }
  1547. IHqlCppDatasetBuilder * HqlCppTranslator::createLinkedDictionaryBuilder(IHqlExpression * record)
  1548. {
  1549. return new LinkedDictionaryBuilder(*this, record);
  1550. }
  1551. IHqlCppDatasetBuilder * HqlCppTranslator::createSingleRowTempDatasetBuilder(IHqlExpression * record, BoundRow * row)
  1552. {
  1553. // if (translator.isFixedRecordSize(record))
  1554. return new SingleRowTempDatasetBuilder(*this, record, row);
  1555. return createBlockedDatasetBuilder(record);
  1556. }
  1557. IHqlCppDatasetBuilder * HqlCppTranslator::createInlineDatasetBuilder(IHqlExpression * record, IHqlExpression * size, IHqlExpression * address)
  1558. {
  1559. assertex(isFixedRecordSize(record));
  1560. return new InlineDatasetBuilder(*this, record, size, address);
  1561. }
  1562. IHqlCppDatasetBuilder * HqlCppTranslator::createChoosenDatasetBuilder(IHqlExpression * record, IHqlExpression * maxCount)
  1563. {
  1564. BlockedDatasetBuilder * builder = new BlockedDatasetBuilder(*this, record);
  1565. builder->setLimit(maxCount, false);
  1566. return builder;
  1567. }
  1568. IHqlCppDatasetBuilder * HqlCppTranslator::createLimitedDatasetBuilder(IHqlExpression * record, IHqlExpression * maxCount)
  1569. {
  1570. BlockedDatasetBuilder * builder = new BlockedDatasetBuilder(*this, record);
  1571. builder->setLimit(maxCount, true);
  1572. return builder;
  1573. }
  1574. //---------------------------------------------------------------------------
  1575. void HqlCppTranslator::doBuildSetAssignAndCast(BuildCtx & ctx, IHqlCppSetBuilder * builder, IHqlExpression * value)
  1576. {
  1577. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, value);
  1578. CHqlBoundExpr srcIsAll;
  1579. cursor->buildIsAll(ctx, srcIsAll);
  1580. OwnedHqlExpr translated = srcIsAll.getTranslatedExpr();
  1581. builder->setAll(ctx, translated);
  1582. BuildCtx loopctx(ctx);
  1583. CHqlBoundExpr boundCurElement;
  1584. cursor->buildIterateLoop(loopctx, boundCurElement, false);
  1585. Owned<IReferenceSelector> selector = builder->buildCreateElement(loopctx);
  1586. OwnedHqlExpr translatedCurElement = boundCurElement.getTranslatedExpr();
  1587. selector->set(loopctx, translatedCurElement);
  1588. builder->finishElement(loopctx);
  1589. }
  1590. void HqlCppTranslator::buildSetAssign(BuildCtx & ctx, IHqlCppSetBuilder * builder, IHqlExpression * expr)
  1591. {
  1592. switch (expr->getOperator())
  1593. {
  1594. case no_cast:
  1595. doBuildSetAssignAndCast(ctx, builder, expr->queryChild(0));
  1596. break;
  1597. case no_addsets:
  1598. doBuildSetAssignAndCast(ctx, builder, expr);
  1599. break;
  1600. //MORE: This is wrong because needs to cope with all.
  1601. buildSetAssign(ctx, builder, expr->queryChild(0));
  1602. buildSetAssign(ctx, builder, expr->queryChild(1));
  1603. break;
  1604. case no_all:
  1605. builder->setAll(ctx, queryBoolExpr(true));
  1606. break;
  1607. case no_list:
  1608. {
  1609. unsigned max = expr->numChildren();
  1610. if ((max < 3) || isComplexSet(expr) || !isConstantSet(expr))
  1611. {
  1612. for (unsigned i=0; i < max; i++)
  1613. {
  1614. //Need a subcontext otherwise sizeof(target-row) gets cached.
  1615. BuildCtx subctx(ctx);
  1616. subctx.addGroup();
  1617. Owned<IReferenceSelector> selector = builder->buildCreateElement(subctx);
  1618. selector->set(subctx, expr->queryChild(i));
  1619. builder->finishElement(subctx);
  1620. }
  1621. builder->setAll(ctx, queryBoolExpr(false));
  1622. }
  1623. else
  1624. doBuildSetAssignAndCast(ctx, builder, expr);
  1625. }
  1626. break;
  1627. case no_createset:
  1628. {
  1629. IHqlExpression * ds = expr->queryChild(0);
  1630. IHqlExpression * value = expr->queryChild(1);
  1631. builder->setAll(ctx, queryBoolExpr(false));
  1632. BuildCtx subctx(ctx);
  1633. BoundRow * cursor = buildDatasetIterate(subctx, ds, false);
  1634. Owned<IReferenceSelector> selector = builder->buildCreateElement(subctx);
  1635. selector->set(subctx, value);
  1636. builder->finishElement(subctx);
  1637. break;
  1638. }
  1639. default:
  1640. doBuildSetAssignAndCast(ctx, builder, expr);
  1641. break;
  1642. }
  1643. }
  1644. void HqlCppTranslator::buildSetAssignViaBuilder(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * value)
  1645. {
  1646. ITypeInfo * to = target.queryType();
  1647. Owned<IHqlCppSetBuilder> builder = createTempSetBuilder(to->queryChildType(), target.isAll);
  1648. builder->buildDeclare(ctx);
  1649. buildSetAssign(ctx, builder, value);
  1650. builder->buildFinish(ctx, target);
  1651. }
  1652. void HqlCppTranslator::doBuildAssignAddSets(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * value)
  1653. {
  1654. IHqlExpression * left = value->queryChild(0);
  1655. IHqlExpression * right = value->queryChild(1);
  1656. assertex(left->queryType() == right->queryType());
  1657. //a poor implementation, but at least it works.
  1658. HqlExprArray args;
  1659. args.append(*LINK(left));
  1660. args.append(*LINK(right));
  1661. OwnedHqlExpr call = bindFunctionCall(appendSetXAtom, args, left->queryType());
  1662. buildExprAssign(ctx, target, call);
  1663. }