hqlcset.cpp 75 KB

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