hqlcset.cpp 73 KB

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