hqlcppcase.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  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 "hql.hpp"
  20. #include "hqlfunc.hpp"
  21. #include "hqlcpp.ipp"
  22. #include "hqlwcpp.hpp"
  23. #include "hqlutil.hpp"
  24. #include "hqlcpputil.hpp"
  25. #include "hqlcatom.hpp"
  26. #include "hqlcerrors.hpp"
  27. #include "hqlthql.hpp"
  28. #define INTEGER_SEARCH_THRESHOLD 30 // above this, a table search is generated.
  29. #define MAX_NUM_NOBREAK_CASE 80 // maximum number of case: without a break - compiler workaround
  30. #define INLINE_COMPARE_THRESHOLD 2 // above this, a loop is generated
  31. #define SWITCH_TABLE_DENSITY_THRESHOLD 3 // % used before use array index.
  32. #define RANGE_DENSITY_THRESHOLD 30 // % used before to use array index with range checking
  33. #define MAX_NESTED_CASES 8 // to stop C++ compiler running out of scopes.
  34. //===========================================================================
  35. static IIdAtom * searchDataTableAtom;
  36. static IIdAtom * searchEStringTableAtom;
  37. static IIdAtom * searchQStringTableAtom;
  38. static IIdAtom * searchStringTableAtom;
  39. static IIdAtom * searchVStringTableAtom;
  40. //===========================================================================
  41. MODULE_INIT(INIT_PRIORITY_STANDARD)
  42. {
  43. searchDataTableAtom = createIdAtom("searchDataTable");
  44. searchEStringTableAtom = createIdAtom("searchEStringTable");
  45. searchQStringTableAtom = createIdAtom("searchQStringTable");
  46. searchStringTableAtom = createIdAtom("searchStringTable");
  47. searchVStringTableAtom = createIdAtom("searchVStringTable");
  48. return true;
  49. }
  50. MODULE_EXIT()
  51. {
  52. }
  53. //===========================================================================
  54. //Case helper functions...
  55. void cvtChooseListToPairs(HqlExprArray & target, IHqlExpression * from, unsigned base)
  56. {
  57. unsigned max = from->numChildren();
  58. unsigned idx;
  59. target.ensure(max);
  60. for (idx = 0; idx < max; idx++)
  61. {
  62. IHqlExpression * v1 = createConstant(createIntValue(idx+base, LINK(unsignedType)));
  63. IHqlExpression * v2 = from->queryChild(idx);
  64. ITypeInfo * type = v2->queryType();
  65. target.append(* createValue(no_mapto, LINK(type), v1, LINK(v2)));
  66. }
  67. }
  68. void cvtIndexListToPairs(HqlExprArray & target, IHqlExpression * from)
  69. {
  70. unsigned max = from->numChildren();
  71. unsigned idx;
  72. target.ensure(max);
  73. for (idx = 0; idx < max; idx++)
  74. {
  75. IHqlExpression * v1 = from->queryChild(idx);
  76. IHqlExpression * v2 = createConstant(createIntValue(idx+1, LINK(unsignedType)));
  77. ITypeInfo * type = v2->queryType();
  78. target.append(* createValue(no_mapto, LINK(type), LINK(v1), v2));
  79. }
  80. }
  81. void cvtInListToPairs(HqlExprArray & target, IHqlExpression * from, bool valueIfMatch)
  82. {
  83. unsigned max = from->numChildren();
  84. unsigned idx;
  85. IHqlExpression * tValue = queryBoolExpr(valueIfMatch);
  86. ITypeInfo * type = queryBoolType();
  87. target.ensure(max);
  88. for (idx = 0; idx < max; idx++)
  89. {
  90. IHqlExpression * v1 = from->queryChild(idx);
  91. target.append(* createValue(no_mapto, LINK(type), LINK(v1), LINK(tValue)));
  92. }
  93. }
  94. IHqlExpression * createNotFoundValue()
  95. {
  96. OwnedITypeInfo int4 = makeIntType(4, true);
  97. return createConstant(int4->castFrom(true, -1));
  98. }
  99. //===========================================================================
  100. static int compareValues(IHqlExpression * lexpr, IHqlExpression * rexpr)
  101. {
  102. return lexpr->queryValue()->compare(rexpr->queryValue());
  103. }
  104. static int comparePair(IHqlExpression * lexpr, IHqlExpression * rexpr)
  105. {
  106. return compareValues(lexpr->queryChild(0), rexpr->queryChild(0));
  107. }
  108. static int comparePair(IInterface * const * left, IInterface * const * right)
  109. {
  110. IHqlExpression * lexpr = (IHqlExpression *)*left;
  111. IHqlExpression * rexpr = (IHqlExpression *)*right;
  112. return comparePair(lexpr, rexpr);
  113. }
  114. HqlCppCaseInfo::HqlCppCaseInfo(HqlCppTranslator & _translator) : translator(_translator)
  115. {
  116. complexCompare = false;
  117. constantCases = true;
  118. constantValues = true;
  119. indexType.setown(makeIntType(sizeof(int), true));
  120. }
  121. void HqlCppCaseInfo::addPair(IHqlExpression * expr)
  122. {
  123. IHqlExpression * compareExpr = expr->queryChild(0);
  124. IHqlExpression * resultExpr = expr->queryChild(1);
  125. if (allResultsMatch && pairs.ordinality())
  126. {
  127. if (pairs.tos().queryChild(1) != resultExpr)
  128. allResultsMatch = false;
  129. }
  130. pairs.append(*LINK(expr));
  131. if (!compareExpr->queryValue())
  132. {
  133. constantCases = false;
  134. }
  135. else if (constantCases)
  136. {
  137. if (!lowestCompareExpr || compareValues(compareExpr, lowestCompareExpr) < 0)
  138. lowestCompareExpr.set(compareExpr);
  139. if (!highestCompareExpr || compareValues(compareExpr, highestCompareExpr) > 0)
  140. highestCompareExpr.set(compareExpr);
  141. }
  142. if (!expr->queryChild(1)->queryValue())
  143. constantValues = false;
  144. if (cond && !complexCompare)
  145. {
  146. ITypeInfo * valueType = compareExpr->queryType();
  147. if (valueType != cond->queryType())
  148. complexCompare = isCompare3Valued(compareExpr->queryType());
  149. }
  150. updateResultType(resultExpr);
  151. }
  152. void HqlCppCaseInfo::addPairs(HqlExprArray & _pairs)
  153. {
  154. pairs.ensure(_pairs.ordinality());
  155. ForEachItemIn(idx, _pairs)
  156. addPair(&_pairs.item(idx));
  157. }
  158. bool HqlCppCaseInfo::canBuildStaticList(ITypeInfo * type)
  159. {
  160. switch (type->getTypeCode())
  161. {
  162. case type_int:
  163. return isStandardSizeInt(type);
  164. case type_swapint:
  165. return false;
  166. default:
  167. return isFixedSize(type);
  168. }
  169. }
  170. bool HqlCppCaseInfo::buildAssign(BuildCtx & ctx, const CHqlBoundTarget & target)
  171. {
  172. ExprAssignProcessor assigner(target);
  173. return buildProcess(ctx, assigner);
  174. }
  175. bool HqlCppCaseInfo::buildProcess(BuildCtx & ctx, IExprProcessor & target)
  176. {
  177. if (pairs.ordinality() == 0)
  178. {
  179. target.process(translator, ctx, defaultValue);
  180. }
  181. else if (cond.get() && constantCases)
  182. {
  183. processBranches();
  184. BuildCtx subctx(ctx);
  185. CHqlBoundExpr test;
  186. buildSwitchCondition(ctx, test);
  187. if (complexCompare)
  188. {
  189. if (pairs.ordinality() > INLINE_COMPARE_THRESHOLD)
  190. {
  191. if (okToAlwaysEvaluateDefault(target) || hasLibraryChop())
  192. buildLoopChopMap(subctx, target, test);
  193. else
  194. buildGeneralAssign(subctx, target);
  195. }
  196. else
  197. {
  198. if (okToAlwaysEvaluateDefault(target))
  199. buildChop3Map(subctx, target, test);
  200. else
  201. buildGeneralAssign(subctx, target);
  202. }
  203. }
  204. else
  205. {
  206. ITypeInfo * condType = test.queryType()->queryPromotedType();
  207. if (!queryBuildArrayLookup(subctx, target, test))
  208. {
  209. if (condType->getTypeCode() != type_real)
  210. {
  211. OwnedHqlExpr search = test.getTranslatedExpr();
  212. if (constantValues && (condType->getTypeCode() == type_int) && (pairs.ordinality() > INTEGER_SEARCH_THRESHOLD) && canBuildStaticList(resultType))
  213. buildIntegerSearchMap(subctx, target, search);
  214. else
  215. buildSwitchMap(subctx, target, test.expr);
  216. }
  217. else
  218. {
  219. if (okToAlwaysEvaluateDefault(target) && pairs.ordinality() > 4)
  220. {
  221. target.process(translator, ctx, defaultValue);
  222. buildChop2Map(subctx, target, test, 0, pairs.ordinality());
  223. }
  224. else
  225. buildGeneralAssign(subctx, target);
  226. }
  227. }
  228. }
  229. }
  230. else
  231. buildGeneralAssign(ctx, target);
  232. return true;
  233. }
  234. bool HqlCppCaseInfo::buildReturn(BuildCtx & ctx)
  235. {
  236. ExprReturnProcessor processor;
  237. buildProcess(ctx, processor);
  238. return true;
  239. }
  240. void HqlCppCaseInfo::buildChop3Map(BuildCtx & ctx, IExprProcessor & target, CHqlBoundExpr & test, IHqlExpression * temp, unsigned start, unsigned end)
  241. {
  242. if ((end - start) <= 2)
  243. buildChop2Map(ctx, target, test, start, end);
  244. else
  245. {
  246. unsigned mid = start + (end - start) / 2;
  247. generateCompareVar(ctx, temp, test, queryCompare(mid));
  248. OwnedHqlExpr test1 = createValue(no_eq, LINK(temp), getZero());
  249. OwnedHqlExpr test2 = createValue(no_lt, LINK(temp), getZero());
  250. BuildCtx subctx(ctx);
  251. IHqlStmt * if1 = subctx.addFilter(test1); // if (test == 0)
  252. target.process(translator, subctx, queryReturn(mid)); // target = value(n)
  253. subctx.selectElse(if1); // else
  254. IHqlStmt * if2 = subctx.addFilter(test2); // if (test < 0)
  255. buildChop3Map(subctx, target, test, temp, start, mid); // repeat for start..mid
  256. subctx.selectElse(if2); // else
  257. buildChop3Map(subctx, target, test, temp, mid+1, end); // repeat for min..end
  258. }
  259. }
  260. void HqlCppCaseInfo::buildChop3Map(BuildCtx & ctx, IExprProcessor & target, CHqlBoundExpr & test)
  261. {
  262. target.process(translator, ctx, defaultValue);
  263. if (getNumPairs() <= 2)
  264. {
  265. buildChop2Map(ctx, target, test, 0, getNumPairs());
  266. }
  267. else
  268. {
  269. //need to hack it because there is no signed integer type
  270. OwnedHqlExpr tempVar = ctx.getTempDeclare(indexType, NULL);
  271. buildChop3Map(ctx, target, test, tempVar, 0, getNumPairs());
  272. }
  273. }
  274. void HqlCppCaseInfo::buildChop2Map(BuildCtx & ctx, IExprProcessor & target, CHqlBoundExpr & test, unsigned start, unsigned end)
  275. {
  276. BuildCtx subctx(ctx);
  277. if ((end - start) <= 3) // (1,2,3) avg(2) cf. (2,2,3) avg(2.3)
  278. {
  279. //optimize the case where they all create the same value
  280. bool same = true;
  281. unsigned index;
  282. for (index=start+1; index < end; ++index)
  283. {
  284. if (queryReturn(index-1) != queryReturn(index))
  285. {
  286. same = false;
  287. break;
  288. }
  289. }
  290. if (same)
  291. {
  292. CompoundBuilder cb(no_or);
  293. for (index=start; index < end; ++index)
  294. {
  295. IHqlExpression * compare = queryCompare(index);
  296. IHqlExpression * cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  297. cb.addOperand(cond);
  298. }
  299. OwnedHqlExpr compound = cb.getCompound();
  300. translator.buildFilter(subctx, compound);
  301. target.process(translator, subctx, queryReturn(start));
  302. }
  303. else
  304. {
  305. IHqlStmt * stmt = NULL;
  306. for (index=start; index < end; ++index)
  307. {
  308. if (stmt)
  309. subctx.selectElse(stmt);
  310. IHqlExpression * compare = queryCompare(index);
  311. OwnedHqlExpr cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  312. CHqlBoundExpr bound;
  313. translator.buildExpr(subctx, cond, bound);
  314. stmt = subctx.addFilter(bound.expr);
  315. target.process(translator, subctx, queryReturn(index));
  316. }
  317. }
  318. }
  319. else
  320. {
  321. unsigned mid = start + (end - start) / 2;
  322. IHqlExpression * compare = queryCompare(mid);
  323. OwnedHqlExpr cond = createCompareExpr(no_lt, test.getTranslatedExpr(), LINK(compare));
  324. CHqlBoundExpr bound;
  325. translator.buildExpr(subctx, cond, bound);
  326. IHqlStmt * stmt = subctx.addFilter(bound.expr);
  327. buildChop2Map(subctx, target, test, start, mid);
  328. subctx.selectElse(stmt);
  329. buildChop2Map(subctx, target, test, mid, end);
  330. }
  331. }
  332. IHqlExpression * HqlCppCaseInfo::buildIndexedMap(BuildCtx & ctx, const CHqlBoundExpr & test)
  333. {
  334. ITypeInfo * compareType = test.queryType()->queryPromotedType();
  335. type_t compareTypeCode = compareType->getTypeCode();
  336. HqlExprArray values;
  337. IHqlExpression * dft = queryActiveTableSelector(); // value doesn't matter as long as it will not occur
  338. __int64 lower = getIntValue(lowerTableBound, 0);
  339. unsigned num = (unsigned)((getIntValue(upperTableBound, 0)-lower)+1);
  340. CHqlBoundExpr indexExpr;
  341. switch (compareTypeCode)
  342. {
  343. case type_int:
  344. indexExpr.set(test);
  345. break;
  346. case type_string:
  347. indexExpr.expr.setown(createValue(no_index, makeCharType(), LINK(test.expr), getZero()));
  348. indexExpr.expr.setown(createValue(no_cast, makeIntType(1, false), LINK(indexExpr.expr)));
  349. break;
  350. default:
  351. throwUnexpectedType(compareType);
  352. }
  353. if (useRangeIndex && (num != 1))
  354. translator.ensureSimpleExpr(ctx, indexExpr);
  355. OwnedHqlExpr mapped;
  356. OwnedHqlExpr castDefaultValue = ensureExprType(defaultValue, resultType);
  357. ITypeInfo * retType = resultType;
  358. //if num == pairs.ordinality() and all results are identical, avoid the table lookup.
  359. if (allResultsMatch && (num == pairs.ordinality()))
  360. {
  361. mapped.set(pairs.item(0).queryChild(1));
  362. }
  363. else
  364. {
  365. values.ensure(num);
  366. unsigned idx;
  367. for (idx = 0; idx < num; idx++)
  368. values.append(*LINK(dft));
  369. ForEachItemIn(idx2, pairs)
  370. {
  371. IHqlExpression & cur = pairs.item(idx2);
  372. IValue * value = cur.queryChild(0)->queryValue();
  373. unsigned replaceIndex;
  374. switch (compareTypeCode)
  375. {
  376. case type_int:
  377. replaceIndex = (unsigned)(value->getIntValue()-lower);
  378. break;
  379. case type_string:
  380. {
  381. StringBuffer temp;
  382. value->getStringValue(temp);
  383. replaceIndex = (unsigned)((unsigned char)temp.charAt(0)-lower);
  384. break;
  385. }
  386. default:
  387. throwUnexpectedType(compareType);
  388. }
  389. IHqlExpression * mapTo = cur.queryChild(1);
  390. if (mapTo->getOperator() != no_constant)
  391. throwUnexpected();
  392. if (replaceIndex >= num)
  393. translator.reportWarning(CategoryIgnored, HQLWRN_CaseCanNeverMatch, "CASE entry %d can never match the test condition", replaceIndex);
  394. else
  395. values.replace(*ensureExprType(mapTo, resultType),replaceIndex);
  396. }
  397. //Now replace the placeholders with the default values.
  398. for (idx = 0; idx < num; idx++)
  399. {
  400. if (&values.item(idx) == dft)
  401. values.replace(*LINK(castDefaultValue),idx);
  402. }
  403. // use a var string type to get better C++ generated...
  404. ITypeInfo * storeType = getArrayElementType(resultType);
  405. ITypeInfo * listType = makeArrayType(storeType, values.ordinality());
  406. OwnedHqlExpr lvalues = createValue(no_list, listType, values);
  407. CHqlBoundExpr boundTable;
  408. translator.buildExpr(ctx, lvalues, boundTable);
  409. LinkedHqlExpr tableIndex = indexExpr.expr;
  410. if (getIntValue(lowerTableBound, 0))
  411. tableIndex.setown(createValue(no_sub, tableIndex->getType(), LINK(tableIndex), LINK(lowerTableBound)));
  412. IHqlExpression * ret = createValue(no_index, LINK(retType), LINK(boundTable.expr), LINK(tableIndex));
  413. mapped.setown(createTranslatedOwned(ret));
  414. }
  415. if (useRangeIndex)
  416. {
  417. if (num != 1)
  418. {
  419. OwnedHqlExpr testValue = indexExpr.getTranslatedExpr();
  420. OwnedHqlExpr aboveLower = createCompare(no_ge, testValue, lowestCompareExpr);
  421. OwnedHqlExpr belowUpper = createCompare(no_le, testValue, highestCompareExpr);
  422. OwnedHqlExpr inRange = createValue(no_and, makeBoolType(), aboveLower.getClear(), belowUpper.getClear());
  423. mapped.setown(createValue(no_if, LINK(retType), inRange.getClear(), LINK(mapped), LINK(defaultValue)));
  424. }
  425. else
  426. {
  427. assertex(allResultsMatch);
  428. OwnedHqlExpr testValue = indexExpr.getTranslatedExpr();
  429. OwnedHqlExpr inRange = createCompare(no_eq, testValue, lowestCompareExpr);
  430. mapped.setown(createValue(no_if, LINK(retType), inRange.getClear(), LINK(mapped), LINK(defaultValue)));
  431. }
  432. }
  433. return mapped.getClear();
  434. }
  435. void HqlCppCaseInfo::buildLoopChopMap(BuildCtx & ctx, IExprProcessor & target, CHqlBoundExpr & test)
  436. {
  437. //Declare a table that contains all the strings...
  438. ITypeInfo * compareType = queryCompareType();
  439. type_t ctc = compareType->getTypeCode();
  440. if ((ctc == type_data) && !hasLibraryChop())
  441. {
  442. buildGeneralAssign(ctx, target);
  443. return;
  444. }
  445. OwnedHqlExpr values = createCompareList();
  446. CHqlBoundExpr boundTable;
  447. translator.buildExpr(ctx, values, boundTable);
  448. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  449. if (hasLibraryChop())
  450. {
  451. ITypeInfo * tableEntryType = makeReferenceModifier(LINK(compareType));
  452. ITypeInfo * tableType = makePointerType(tableEntryType);
  453. HqlExprArray args;
  454. IIdAtom * func;
  455. switch (ctc)
  456. {
  457. case type_data:
  458. func = searchDataTableAtom;
  459. break;
  460. case type_varstring:
  461. func = searchVStringTableAtom;
  462. break;
  463. case type_qstring:
  464. func = searchQStringTableAtom;
  465. break;
  466. case type_string:
  467. if (compareType->queryCharset()->queryName() == asciiAtom)
  468. func = searchStringTableAtom;
  469. else if (compareType->queryCharset()->queryName() == ebcdicAtom)
  470. func = searchEStringTableAtom;
  471. else
  472. UNIMPLEMENTED;
  473. break;
  474. case type_unicode:
  475. func = searchUnicodeTableId;
  476. break;
  477. case type_utf8:
  478. func = searchUtf8TableId;
  479. break;
  480. case type_varunicode:
  481. func = searchVUnicodeTableId;
  482. break;
  483. default:
  484. throwUnexpectedType(compareType);
  485. }
  486. args.append(*getSizetConstant(values->numChildren()));
  487. if ((ctc != type_varstring) && (ctc != type_varunicode))
  488. args.append(*getSizetConstant(values->queryChild(0)->queryType()->getStringLen()));
  489. args.append(*createValue(no_address, tableType, createValue(no_index, LINK(tableEntryType), LINK(boundTable.expr), getZero())));
  490. if ((ctc != type_varstring) && (ctc != type_varunicode))
  491. args.append(*translator.getBoundLength(test));
  492. args.append(*ensureIndexable(test.expr));
  493. if ((ctc==type_unicode) || (ctc == type_varunicode) || (ctc == type_utf8))
  494. args.append(*createConstant(str(compareType->queryLocale())));
  495. OwnedHqlExpr call = translator.bindTranslatedFunctionCall(func, args);
  496. OwnedHqlExpr search = createTranslated(call);
  497. bool includeDefaultInResult = false;
  498. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  499. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  500. if (simpleResult)
  501. target.process(translator, ctx, simpleResult);
  502. else
  503. {
  504. ctx.addDeclare(midVar, NULL);
  505. translator.buildAssignToTemp(ctx, midVar, search);
  506. if (includeDefaultInResult)
  507. {
  508. target.process(translator, ctx, resultExpr);
  509. }
  510. else
  511. {
  512. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  513. BuildCtx subctx(ctx);
  514. IHqlStmt * stmt = subctx.addFilter(compare);
  515. target.process(translator, subctx, resultExpr);
  516. subctx.selectElse(stmt);
  517. target.process(translator, subctx, defaultValue);
  518. }
  519. }
  520. }
  521. else
  522. {
  523. #if 0
  524. //Keep this as a reminder of what was needed to fix qstrings.
  525. if (ctc == type_qstring)
  526. {
  527. Linked<ITypeInfo> compareType = queryCompareType();
  528. compareType.setown(makeArrayType(compareType.getLink()));
  529. table = createValue(no_typetransfer, compareType.getLink(), table);
  530. }
  531. #endif
  532. OwnedHqlExpr resultExpr = createResultsExpr(midVar, false);
  533. //Now generate the code that performs the binary chop..
  534. ctx.addDeclare(midVar, NULL);
  535. OwnedHqlExpr compareVar = ctx.getTempDeclare(indexType, NULL);
  536. OwnedHqlExpr leftVar = ctx.getTempDeclare(indexType, NULL);
  537. OwnedHqlExpr rightVar = ctx.getTempDeclare(indexType, NULL);
  538. OwnedHqlExpr numPairs = getSizetConstant(getNumPairs());
  539. ctx.addAssign(leftVar, queryZero());
  540. ctx.addAssign(rightVar, numPairs);
  541. target.process(translator,ctx, defaultValue);
  542. OwnedHqlExpr loopc = createBoolExpr(no_lt, LINK(leftVar), LINK(rightVar));
  543. OwnedHqlExpr mid = createValue(no_div, createValue(no_add, LINK(leftVar), LINK(rightVar)), createConstant(indexType->castFrom(false, 2)));
  544. OwnedHqlExpr mid_p1 = createValue(no_add, LINK(indexType), LINK(midVar), createConstant(indexType->castFrom(false, 1)));
  545. OwnedHqlExpr curelem = createValue(no_index, LINK(compareType), boundTable.getTranslatedExpr(), createTranslated(mid_p1));
  546. OwnedHqlExpr test1 = createBoolExpr(no_lt, LINK(compareVar), getZero());
  547. OwnedHqlExpr test2 = createBoolExpr(no_gt, LINK(compareVar), getZero());
  548. OwnedHqlExpr order = createValue(no_order, LINK(indexType), test.getTranslatedExpr(), LINK(curelem));
  549. BuildCtx loopctx(ctx);
  550. loopctx.addLoop(loopc, NULL, true);
  551. translator.buildAssignToTemp(loopctx, midVar, mid);
  552. translator.buildAssignToTemp(loopctx, compareVar, order);
  553. BuildCtx subctx(loopctx);
  554. IHqlStmt * if1 = subctx.addFilter(test1); // if (test < 0)
  555. translator.buildAssignToTemp(subctx, rightVar, midVar); // right = mid;
  556. subctx.selectElse(if1); // else
  557. IHqlStmt * if2 = subctx.addFilter(test2); // if (test > 0)
  558. translator.buildAssignToTemp(subctx, leftVar, mid_p1); // left = mid + 1;
  559. subctx.selectElse(if2); // else
  560. //generate the default assignment...
  561. target.process(translator, subctx, resultExpr);
  562. subctx.addBreak();
  563. }
  564. }
  565. void HqlCppCaseInfo::buildIntegerSearchMap(BuildCtx & ctx, IExprProcessor & target, IHqlExpression * test)
  566. {
  567. ITypeInfo * compareType = queryCompareType();
  568. HqlExprArray args;
  569. args.append(*createCompareList());
  570. args.append(*LINK(test));
  571. IIdAtom * func;
  572. if (compareType->isSigned())
  573. {
  574. if (compareType->getSize() > 4)
  575. func = searchTableInteger8Id;
  576. else
  577. func = searchTableInteger4Id;
  578. }
  579. else
  580. {
  581. if (compareType->getSize() > 4)
  582. func = searchTableUInteger8Id;
  583. else
  584. func = searchTableUInteger4Id;
  585. }
  586. OwnedHqlExpr search = translator.bindFunctionCall(func, args);
  587. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  588. bool includeDefaultInResult = false;
  589. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  590. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  591. if (simpleResult)
  592. target.process(translator, ctx, simpleResult);
  593. else
  594. {
  595. ctx.addDeclare(midVar, NULL);
  596. translator.buildAssignToTemp(ctx, midVar, search);
  597. if (includeDefaultInResult)
  598. {
  599. target.process(translator, ctx, resultExpr);
  600. }
  601. else
  602. {
  603. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  604. BuildCtx subctx(ctx);
  605. IHqlStmt * stmt = subctx.addFilter(compare);
  606. target.process(translator, subctx, resultExpr);
  607. subctx.selectElse(stmt);
  608. target.process(translator, subctx, defaultValue);
  609. }
  610. }
  611. }
  612. void HqlCppCaseInfo::buildSwitchCondition(BuildCtx & ctx, CHqlBoundExpr & bound)
  613. {
  614. OwnedHqlExpr simpleCond = complexCompare ? getSimplifyCompareArg(cond) : LINK(cond);
  615. translator.buildCachedExpr(ctx, simpleCond, bound);
  616. }
  617. void HqlCppCaseInfo::buildSwitchMap(BuildCtx & ctx, IExprProcessor & target, IHqlExpression * test)
  618. {
  619. bool isCharCompare = (test->queryType()->getTypeCode() == type_string);
  620. Owned<ITypeInfo> unsigned1Type = makeIntType(1, false);
  621. LinkedHqlExpr cond = test;
  622. if (isCharCompare)
  623. cond.setown(createValue(no_implicitcast, LINK(unsigned1Type), createValue(no_index, makeCharType(), LINK(test), getZero())));
  624. BuildCtx subctx(ctx);
  625. IHqlStmt * stmt = subctx.addSwitch(cond);
  626. // are all the comparisons against constant values? If so we optimize it...
  627. unsigned sameCount = 0;
  628. ForEachItemIn(idx, pairs)
  629. {
  630. IHqlExpression & cur = pairs.item(idx);
  631. LinkedHqlExpr compare = cur.queryChild(0);
  632. IHqlExpression * branchValue = cur.queryChild(1);
  633. if (isCharCompare)
  634. {
  635. //Coded this way to avoid problems with ascii v ebcdic strings
  636. const byte * data = reinterpret_cast<const byte *>((char *)compare->queryValue()->queryValue());
  637. byte value = data[0];
  638. Owned<IValue> cast;
  639. if (value < 127)
  640. cast.setown(createCharValue(value, true));
  641. else
  642. cast.setown(createIntValue(data[0], LINK(unsigned1Type)));
  643. compare.setown(createConstant(cast.getClear()));
  644. }
  645. bool same = false;
  646. bool skip = false;
  647. if (idx != pairs.ordinality()-1)
  648. {
  649. IHqlExpression & next = pairs.item(idx+1);
  650. if (next.queryChild(1) == branchValue)
  651. same = true;
  652. //if save item is included twice, remove one so no error
  653. //from the case statement
  654. if (next.queryChild(0) == cur.queryChild(0))
  655. {
  656. skip = true;
  657. #ifdef _DEBUG
  658. throwUnexpected(); // should have been removed as a duplicate
  659. #endif
  660. }
  661. }
  662. if (compare->queryValue()->rangeCompare(cond->queryType()) != 0)
  663. {
  664. StringBuffer ecl;
  665. getExprECL(compare, ecl);
  666. translator.reportWarning(CategoryIgnored, HQLWRN_CaseCanNeverMatch, "CASE entry %s can never match the test condition", ecl.str());
  667. skip = true;
  668. }
  669. if (sameCount >= MAX_NUM_NOBREAK_CASE)
  670. same = false;
  671. if (!skip)
  672. {
  673. subctx.addCase(stmt, compare);
  674. // common up case labels that produce the same result
  675. if (!same)
  676. {
  677. sameCount = 1;
  678. target.process(translator, subctx, branchValue);
  679. }
  680. else
  681. sameCount++;
  682. }
  683. }
  684. if (target.canContinue())
  685. {
  686. subctx.addDefault(stmt);
  687. target.process(translator, subctx, defaultValue);
  688. }
  689. else
  690. target.process(translator, ctx, defaultValue);
  691. }
  692. void HqlCppCaseInfo::buildGeneralAssign(BuildCtx & ctx, IExprProcessor & target)
  693. {
  694. unsigned max = pairs.ordinality();
  695. Owned<BuildCtx> subctx = new BuildCtx(ctx);
  696. CHqlBoundExpr pureCond;
  697. if (cond.get())
  698. translator.buildCachedExpr(*subctx, cond, pureCond);
  699. OwnedHqlExpr testMore;
  700. if (target.canContinue() && (max > MAX_NESTED_CASES))
  701. {
  702. //Too many nested blocks cause the compiler indigestion...
  703. Owned<ITypeInfo> t = makeBoolType();
  704. testMore.setown(ctx.getTempDeclare(t, queryBoolExpr(false)));
  705. }
  706. for (unsigned idx = 0; idx < max; idx++)
  707. {
  708. IHqlExpression & cur = pairs.item(idx);
  709. IHqlExpression * curtest = cur.queryChild(0);
  710. IHqlExpression * curvalue = cur.queryChild(1);
  711. OwnedHqlExpr compare;
  712. if (!pureCond.expr)
  713. compare.setown(ensureExprType(curtest, queryBoolType()));
  714. else
  715. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  716. if (target.canContinue())
  717. {
  718. if (idx && ((idx % MAX_NESTED_CASES) == 0))
  719. {
  720. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(true));
  721. subctx.setown(new BuildCtx(ctx));
  722. subctx->addFilter(testMore);
  723. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(false));
  724. }
  725. IHqlStmt * test = translator.buildFilterViaExpr(*subctx, compare);
  726. target.process(translator, *subctx, curvalue);
  727. subctx->selectElse(test);
  728. }
  729. else
  730. {
  731. BuildCtx ifctx(*subctx);
  732. translator.buildFilter(ifctx, compare);
  733. target.process(translator, ifctx, curvalue);
  734. }
  735. }
  736. target.process(translator, *subctx, defaultValue);
  737. }
  738. void HqlCppCaseInfo::buildGeneralReturn(BuildCtx & ctx)
  739. {
  740. unsigned max = pairs.ordinality();
  741. CHqlBoundExpr pureCond;
  742. if (cond.get())
  743. translator.buildCachedExpr(ctx, cond, pureCond);
  744. for (unsigned idx = 0; idx < max; idx++)
  745. {
  746. IHqlExpression & cur = pairs.item(idx);
  747. IHqlExpression * curtest = cur.queryChild(0);
  748. IHqlExpression * curvalue = cur.queryChild(1);
  749. OwnedHqlExpr compare;
  750. if (!pureCond.expr)
  751. compare.setown(ensureExprType(curtest, queryBoolType()));
  752. else
  753. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  754. BuildCtx subctx(ctx);
  755. translator.buildFilter(subctx, compare);
  756. translator.buildReturn(subctx, curvalue);
  757. }
  758. translator.buildReturn(ctx, defaultValue);
  759. }
  760. bool HqlCppCaseInfo::okToAlwaysEvaluateDefault(const IExprProcessor & target)
  761. {
  762. if (target.canReturn())
  763. return false;
  764. if (!canRemoveGuard(defaultValue))
  765. return false;
  766. return true;
  767. }
  768. ITypeInfo * HqlCppCaseInfo::queryCompareType()
  769. {
  770. return cond->queryType()->queryPromotedType();
  771. }
  772. IHqlExpression * HqlCppCaseInfo::createCompareList()
  773. {
  774. //NB: All cases need to have the same type because they are stored in a table
  775. Linked<ITypeInfo> promoted = pairs.item(0).queryChild(0)->queryType();
  776. unsigned max = pairs.ordinality();
  777. for (unsigned idx1 = 1; idx1 < max; idx1++)
  778. {
  779. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  780. promoted.setown(getPromotedECLType(promoted, type));
  781. }
  782. HqlExprArray values;
  783. values.ensure(pairs.ordinality());
  784. ForEachItemIn(idx, pairs)
  785. {
  786. IHqlExpression & pair = pairs.item(idx);
  787. IHqlExpression * compare = pair.queryChild(0);
  788. values.append(*ensureExprType(compare, promoted));
  789. }
  790. Linked<ITypeInfo> compareType = queryCompareType();
  791. switch (compareType->getTypeCode())
  792. {
  793. case type_string:
  794. case type_data:
  795. case type_varstring:
  796. case type_qstring:
  797. case type_utf8:
  798. compareType.setown(makePointerType(makeCharType(false)));
  799. break;
  800. case type_unicode:
  801. case type_varunicode:
  802. compareType.setown(makePointerType(makeClassType("UChar")));
  803. break;
  804. }
  805. return createValue(no_list, makeArrayType(compareType.getLink()), values);
  806. }
  807. IHqlExpression * HqlCppCaseInfo::createResultsExpr(IHqlExpression * matchVar, bool canIncludeDefault, bool * includedDefault)
  808. {
  809. if (includedDefault)
  810. *includedDefault = false;
  811. //Look at all the return results and see what relation we can create
  812. //This can generate one of the following:
  813. //1. A single value.
  814. //2. A function of the result. e.g., IN...
  815. //3. A lookup in another table. [ all values are constant ]
  816. //4. A nested map statement
  817. bool areSame = true;
  818. bool areLinear = true;
  819. bool areConstant = true;
  820. __int64 linearStart = 0;
  821. __int64 linearMultiple = 1;
  822. ITypeInfo * retType = resultType;
  823. switch (retType->getTypeCode())
  824. {
  825. case type_int:
  826. case type_boolean:
  827. break;
  828. case type_string:
  829. case type_data:
  830. // areConstant = false; // a temporary hack to stop incorrect table being generated.
  831. areLinear = false;
  832. break;
  833. default:
  834. areLinear = false;
  835. break;
  836. }
  837. IHqlExpression * prevValue = NULL;
  838. HqlExprArray values;
  839. values.ensure(pairs.ordinality());
  840. ForEachItemIn(idx, pairs)
  841. {
  842. IHqlExpression & pair = pairs.item(idx);
  843. IHqlExpression * value = pair.queryChild(1);
  844. IValue * cvalue = value->queryValue();
  845. if (cvalue)
  846. {
  847. if (areLinear)
  848. {
  849. __int64 val = cvalue->getIntValue();
  850. if (idx == 0)
  851. linearStart = val;
  852. else if (idx == 1)
  853. linearMultiple = (val - linearStart);
  854. else if (val != linearStart + idx * linearMultiple)
  855. areLinear = false;
  856. }
  857. }
  858. else
  859. {
  860. areConstant = false;
  861. areLinear = false;
  862. }
  863. if (idx > 0)
  864. {
  865. if (areSame && (prevValue != value))
  866. areSame = false;
  867. }
  868. values.append(*ensureExprType(value, resultType));
  869. prevValue = value;
  870. }
  871. if (areSame)
  872. return LINK(prevValue);
  873. if (areLinear)
  874. {
  875. IHqlExpression * ret = ensureExprType(matchVar, resultType);
  876. if (linearMultiple != 1)
  877. ret = createValue(no_mul, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearMultiple)));
  878. if (linearStart != 0)
  879. ret = createValue(no_add, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearStart)));
  880. return ret;
  881. }
  882. unsigned firstMatchEntry = 0;
  883. if (canIncludeDefault)
  884. {
  885. //If all the values are constant, then can add the default as an extra 0th entry, because -1 will be the index for the default
  886. if (areConstant && defaultValue->isConstant() && defaultValue->queryType() == values.item(0).queryType())
  887. {
  888. firstMatchEntry = 1;
  889. values.add(*LINK(defaultValue), 0);
  890. *includedDefault = true;
  891. }
  892. }
  893. // easy way to create a value list...
  894. ITypeInfo * storeType = getArrayElementType(retType);
  895. OwnedHqlExpr newlist = createValue(no_list, makeSetType(storeType), values);
  896. if (areConstant && canBuildStaticList(resultType))
  897. {
  898. IHqlExpression * index = adjustValue(matchVar, 1+firstMatchEntry);
  899. return createValue(no_index, LINK(retType), LINK(newlist), index, createAttribute(noBoundCheckAtom));
  900. }
  901. //Need to generate a case (switch integer case 1: ..... )
  902. HqlExprArray choosePairs;
  903. cvtChooseListToPairs(choosePairs, newlist, 0);
  904. *includedDefault = true;
  905. IHqlExpression * caseExpr = createOpenValue(no_case, LINK(retType));
  906. caseExpr->addOperand(LINK(matchVar));
  907. ForEachItemIn(idx2, choosePairs)
  908. caseExpr->addOperand(&choosePairs.item(idx2));
  909. choosePairs.kill(true);
  910. caseExpr->addOperand(LINK(defaultValue));
  911. return caseExpr->closeExpr();
  912. }
  913. void HqlCppCaseInfo::generateCompareVar(BuildCtx & ctx, IHqlExpression * target, CHqlBoundExpr & test, IHqlExpression * other)
  914. {
  915. OwnedHqlExpr compare = createValue(no_order, test.getTranslatedExpr(), LINK(other));
  916. translator.buildAssignToTemp(ctx, target, compare);
  917. }
  918. unsigned HqlCppCaseInfo::getNumPairs()
  919. {
  920. return pairs.ordinality();
  921. }
  922. bool HqlCppCaseInfo::hasLibraryChop()
  923. {
  924. ITypeInfo * compareType = queryCompareType();
  925. type_t ctc = compareType->getTypeCode();
  926. switch (ctc)
  927. {
  928. case type_data:
  929. return canBuildStaticList(promotedElementType);
  930. case type_string:
  931. case type_varstring:
  932. case type_qstring:
  933. case type_unicode:
  934. case type_varunicode:
  935. case type_utf8:
  936. return true;
  937. }
  938. return false;
  939. }
  940. void HqlCppCaseInfo::processBranches()
  941. {
  942. sortPairs();
  943. removeDuplicates();
  944. promoteTypes();
  945. }
  946. void HqlCppCaseInfo::promoteTypes()
  947. {
  948. Owned<ITypeInfo> promoted = pairs.item(0).queryChild(0)->getType();
  949. unsigned max = pairs.ordinality();
  950. for (unsigned idx1 = 1; idx1 < max; idx1++)
  951. {
  952. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  953. if (isStringType(promoted) && isStringType(type))
  954. {
  955. if (promoted->getStringLen() != type->getStringLen())
  956. {
  957. promoted.setown(::getPromotedECLType(promoted, type));
  958. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  959. }
  960. }
  961. promoted.setown(::getPromotedECLType(promoted, type));
  962. }
  963. promotedElementType.set(promoted);
  964. if (isStringType(promoted))
  965. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  966. ITypeInfo * testType = queryCompareType();
  967. if ((testType->queryCharset() != promoted->queryCharset()) || (testType->queryLocale() != promoted->queryLocale()))
  968. cond.setown(ensureExprType(cond, promoted));
  969. }
  970. bool HqlCppCaseInfo::canBuildArrayLookup(const CHqlBoundExpr & test)
  971. {
  972. if (!constantValues || pairs.ordinality() <= 3)
  973. return false;
  974. ITypeInfo * condType = test.queryType()->queryPromotedType();
  975. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  976. unsigned bitSize = condType->getBitSize();
  977. if ((bitSize && (bitSize <= 8) && !condType->isSigned()))
  978. {
  979. unsigned limit = (1 << bitSize);
  980. //use case if enough items, or above a certain density...
  981. if (pairs.ordinality() * 100 >= limit * SWITCH_TABLE_DENSITY_THRESHOLD)
  982. {
  983. if ((condType->getTypeCode() == type_int) || (condType->getTypeCode() == type_string))
  984. {
  985. lowerTableBound.setown(getSizetConstant(0));
  986. upperTableBound.setown(getSizetConstant(limit-1));
  987. return true;
  988. }
  989. }
  990. }
  991. //Currently this condition is restricted because it revealed inconsistencies in the implementation
  992. //HPCC-18745 is opened to address that later.
  993. //Change to: if (condType->isInteger() && !isUnknownSize(resultType))
  994. if (condType->isInteger() && resultType->isInteger())
  995. {
  996. unsigned __int64 range = getIntValue(highestCompareExpr, 0) - getIntValue(lowestCompareExpr, 0) + 1;
  997. if (pairs.ordinality() * 100 >= range * RANGE_DENSITY_THRESHOLD)
  998. {
  999. useRangeIndex = true;
  1000. lowerTableBound.set(lowestCompareExpr);
  1001. upperTableBound.set(highestCompareExpr);
  1002. return true;
  1003. }
  1004. }
  1005. return false;
  1006. }
  1007. bool HqlCppCaseInfo::queryBuildArrayLookup(BuildCtx & ctx, IExprProcessor & target, const CHqlBoundExpr & test)
  1008. {
  1009. if (canBuildArrayLookup(test) && canBuildStaticList(resultType) && defaultValue->isConstant())
  1010. {
  1011. BuildCtx subctx(ctx);
  1012. OwnedHqlExpr ret = buildIndexedMap(subctx, test);
  1013. target.process(translator, ctx, ret);
  1014. return true;
  1015. }
  1016. return false;
  1017. }
  1018. void HqlCppCaseInfo::removeDuplicates()
  1019. {
  1020. unsigned num = pairs.ordinality();
  1021. if (num > 1)
  1022. {
  1023. num--;
  1024. while (num--)
  1025. {
  1026. IHqlExpression & cur = pairs.item(num);
  1027. IHqlExpression & next = pairs.item(num+1);
  1028. if (cur.queryChild(0) == next.queryChild(0))
  1029. {
  1030. if (cur.queryChild(1) == next.queryChild(1))
  1031. pairs.remove(num+1);
  1032. else
  1033. {
  1034. // we need to keep the first in the original list.... Horrid, but it works...
  1035. unsigned off1 = originalPairs.find(cur);
  1036. unsigned off2 = originalPairs.find(next);
  1037. assertex(off1 != NotFound && off2 != NotFound);
  1038. if (off1 < off2)
  1039. pairs.remove(num+1);
  1040. else
  1041. pairs.remove(num);
  1042. }
  1043. }
  1044. }
  1045. }
  1046. }
  1047. IHqlExpression * HqlCppCaseInfo::queryCreateSimpleResultAssign(IHqlExpression * search, IHqlExpression * resultExpr)
  1048. {
  1049. IHqlExpression * trueExpr = queryBoolExpr(true);
  1050. IHqlExpression * falseExpr = queryBoolExpr(false);
  1051. if (resultExpr == trueExpr && defaultValue == falseExpr)
  1052. return createBoolExpr(no_ne, LINK(search), createNotFoundValue());
  1053. if (resultExpr == falseExpr && defaultValue == trueExpr)
  1054. return createBoolExpr(no_eq, LINK(search), createNotFoundValue());
  1055. return NULL;
  1056. }
  1057. IHqlExpression * HqlCppCaseInfo::queryCompare(unsigned index)
  1058. {
  1059. return pairs.item(index).queryChild(0);
  1060. }
  1061. IHqlExpression * HqlCppCaseInfo::queryReturn(unsigned index)
  1062. {
  1063. return pairs.item(index).queryChild(1);
  1064. }
  1065. void HqlCppCaseInfo::setCond(IHqlExpression * expr)
  1066. {
  1067. cond.set(expr);
  1068. if (isCompare3Valued(expr->queryType()))
  1069. complexCompare = true;
  1070. }
  1071. void HqlCppCaseInfo::setDefault(IHqlExpression * expr)
  1072. {
  1073. defaultValue.set(expr);
  1074. }
  1075. void HqlCppCaseInfo::sortPairs()
  1076. {
  1077. appendArray(originalPairs, pairs);
  1078. pairs.sort(comparePair);
  1079. }
  1080. void HqlCppCaseInfo::updateResultType(IHqlExpression * expr)
  1081. {
  1082. ITypeInfo * curResultType = expr->queryType();
  1083. if (resultType)
  1084. resultType.setown(::getPromotedECLType(resultType, curResultType));
  1085. else
  1086. resultType.set(curResultType);
  1087. }