hqlcset.cpp 66 KB

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