hqlcset.cpp 73 KB

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