hqlcfilter.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  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 "jmisc.hpp"
  18. #include "jstream.ipp"
  19. #include "jdebug.hpp"
  20. #include "eclrtl_imp.hpp"
  21. #include "rtlkey.hpp"
  22. #include "hql.hpp"
  23. #include "hqlattr.hpp"
  24. #include "hqlmeta.hpp"
  25. #include "hqlthql.hpp"
  26. #include "hqlhtcpp.ipp"
  27. #include "hqlttcpp.ipp"
  28. #include "hqlutil.hpp"
  29. #include "hqlthql.hpp"
  30. #include "hqlwcpp.hpp"
  31. #include "hqlcpputil.hpp"
  32. #include "hqltcppc.ipp"
  33. #include "hqlopt.hpp"
  34. #include "hqlfold.hpp"
  35. #include "hqlcerrors.hpp"
  36. #include "hqlcatom.hpp"
  37. #include "hqltrans.ipp"
  38. #include "hqlpmap.hpp"
  39. #include "hqlttcpp.ipp"
  40. #include "hqlcfilter.hpp"
  41. #include "hqlcse.ipp"
  42. const char * BuildFilterState::getSetName(bool createValueSets)
  43. {
  44. if (!setNames.isItem(numActiveSets))
  45. {
  46. StringBuffer name;
  47. getUniqueId(name.append("set"));
  48. setNames.append(*new StringAttrItem(name.str()));
  49. StringBuffer s;
  50. funcctx.setNextConstructor();
  51. if (createValueSets)
  52. funcctx.addQuoted(s.append("Owned<IValueSet> ").append(name).append(";"));
  53. else
  54. funcctx.addQuoted(s.append("Owned<IStringSet> ").append(name).append(";"));
  55. }
  56. return setNames.item(numActiveSets++).text;
  57. }
  58. void BuildFilterState::popSetName()
  59. {
  60. numActiveSets--;
  61. }
  62. //---------------------------------------------------------------------------------------------------------------------
  63. CppFilterExtractor::CppFilterExtractor(IHqlExpression * _tableExpr, HqlCppTranslator & _translator, int _numKeyableFields, bool _isDiskRead, bool forceValueSets)
  64. : FilterExtractor(_translator, _tableExpr, _numKeyableFields, _isDiskRead, _isDiskRead || _translator.queryOptions().createValueSets || forceValueSets, _translator.queryOptions().allKeyedFiltersOptional), translator(_translator)
  65. {
  66. if (createValueSets)
  67. {
  68. addRangeFunc = addRawRangeId;
  69. killRangeFunc = killRawRangeId;
  70. }
  71. else
  72. {
  73. addRangeFunc = addRangeId;
  74. killRangeFunc = killRangeId;
  75. }
  76. }
  77. void CppFilterExtractor::callAddAll(BuildCtx & ctx, IHqlExpression * targetVar)
  78. {
  79. HqlExprArray args;
  80. args.append(*LINK(targetVar));
  81. translator.callProcedure(ctx, addAllId, args);
  82. }
  83. bool CppFilterExtractor::createGroupingMonitor(BuildCtx ctx, const char * listName, IHqlExpression * expr, unsigned & maxField)
  84. {
  85. switch (expr->getOperator())
  86. {
  87. case no_if:
  88. {
  89. IHqlExpression * cond = expr->queryChild(0);
  90. if (expr->queryChild(2)->isConstant() && isIndependentOfScope(cond))
  91. {
  92. BuildCtx subctx(ctx);
  93. translator.buildFilter(subctx, expr->queryChild(0));
  94. createGroupingMonitor(subctx, listName, expr->queryChild(1), maxField);
  95. return true; // may still be keyed
  96. }
  97. break;
  98. }
  99. case no_select:
  100. {
  101. size32_t offset = 0;
  102. ForEachItemIn(i, keyableSelects)
  103. {
  104. IHqlExpression & cur = keyableSelects.item(i);
  105. size32_t curSize = cur.queryType()->getSize();
  106. if (!createValueSets && curSize == UNKNOWN_LENGTH)
  107. break;
  108. if (expr == &cur)
  109. {
  110. maxField = i+1;
  111. if (createValueSets)
  112. {
  113. StringBuffer type;
  114. translator.buildRtlFieldType(type, expr->queryChild(1), queryRecord(tableExpr));
  115. ctx.addQuotedF("%s->append(FFkeyed, createWildFieldFilter(%u, %s));", listName, i, type.str());
  116. }
  117. else
  118. {
  119. //MORE: Check the type of the field is legal.
  120. ctx.addQuotedF("%s->append(createWildKeySegmentMonitor(%u, %u, %u));", listName, i, offset, curSize);
  121. }
  122. return true;
  123. }
  124. offset += curSize;
  125. }
  126. break;
  127. }
  128. case no_constant:
  129. return true;
  130. }
  131. ctx.addReturn(queryBoolExpr(false));
  132. return false;
  133. }
  134. void CppFilterExtractor::buildKeySegmentInExpr(BuildFilterState & buildState, KeySelectorInfo & selectorInfo, BuildCtx & ctx, const char * target, IHqlExpression & thisKey, MonitorFilterKind filterKind)
  135. {
  136. //Generally this slightly increases the code size, but reduces the number of
  137. //temporary sets which is generally more efficient.
  138. OwnedHqlExpr simplified = querySimplifyInExpr(&thisKey);
  139. if (simplified)
  140. {
  141. OwnedHqlExpr folded = foldHqlExpression(simplified);
  142. buildKeySegmentExpr(buildState, selectorInfo, ctx, target, *folded, filterKind);
  143. return;
  144. }
  145. IHqlExpression * expandedSelector = selectorInfo.expandedSelector;
  146. ITypeInfo * fieldType = expandedSelector->queryType();
  147. unsigned curSize = fieldType->getSize();
  148. createStringSet(ctx, target, curSize, expandedSelector);
  149. OwnedHqlExpr targetVar = createVariable(target, makeVoidType());
  150. IHqlExpression * lhs = thisKey.queryChild(0);
  151. OwnedHqlExpr values = normalizeListCasts(thisKey.queryChild(1));
  152. IIdAtom * func = addRangeFunc;
  153. if (thisKey.getOperator() == no_notin)
  154. {
  155. callAddAll(ctx, targetVar);
  156. func = killRangeFunc;
  157. }
  158. if (values->getOperator() != no_list)
  159. {
  160. //iterate through the set
  161. BuildCtx subctx(ctx);
  162. CHqlBoundExpr boundCurElement;
  163. Owned<IHqlCppSetCursor> cursor = translator.createSetSelector(ctx, values);
  164. bool done = false;
  165. CHqlBoundExpr isAll;
  166. cursor->buildIsAll(subctx, isAll);
  167. if (isAll.expr->queryValue())
  168. {
  169. if (isAll.expr->queryValue()->getBoolValue())
  170. {
  171. callAddAll(subctx, targetVar);
  172. done = true;
  173. //If ALL allowed exceptions then we would need to do more....
  174. }
  175. }
  176. else
  177. {
  178. IHqlStmt * stmt = subctx.addFilter(isAll.expr);
  179. callAddAll(subctx, targetVar);
  180. subctx.selectElse(stmt);
  181. }
  182. if (!done)
  183. {
  184. cursor->buildIterateLoop(subctx, boundCurElement, false);
  185. OwnedHqlExpr curValue = boundCurElement.getTranslatedExpr();
  186. OwnedHqlExpr test = createBoolExpr(no_eq, LINK(lhs), LINK(curValue));
  187. OwnedHqlExpr promoted = getExplicitlyPromotedCompare(test);
  188. OwnedHqlExpr subrange, compare, normalized;
  189. extractCompareInformation(subctx, promoted, subrange, compare, normalized, expandedSelector);
  190. CHqlBoundExpr boundSubLength;
  191. buildSubRange(ctx, subrange, boundSubLength);
  192. if (compare)
  193. translator.buildFilter(subctx, compare);
  194. HqlExprArray args;
  195. args.append(*LINK(targetVar));
  196. unsigned srcSize = normalized->queryType()->getSize();
  197. if (srcSize < curSize && curSize != UNKNOWN_LENGTH)
  198. {
  199. OwnedHqlExpr lengthExpr = getSizetConstant(srcSize);
  200. OwnedHqlExpr rangeLower = getRangeLimit(fieldType, lengthExpr, normalized, -1);
  201. OwnedHqlExpr rangeUpper = getRangeLimit(fieldType, lengthExpr, normalized, +1);
  202. CHqlBoundExpr boundLower, boundUpper;
  203. translator.buildExpr(subctx, rangeLower, boundLower);
  204. translator.buildExpr(subctx, rangeUpper, boundUpper);
  205. args.append(*getPointer(boundLower.expr));
  206. args.append(*getPointer(boundUpper.expr));
  207. }
  208. else
  209. {
  210. OwnedHqlExpr address = getMonitorValueAddress(subctx, expandedSelector, normalized);
  211. args.append(*LINK(address));
  212. args.append(*LINK(address));
  213. }
  214. if (boundSubLength.expr)
  215. args.append(*LINK(boundSubLength.expr));
  216. translator.callProcedure(subctx, func, args);
  217. }
  218. }
  219. else
  220. {
  221. CHqlBoundExpr boundSubLength;
  222. ForEachChild(idx2, values)
  223. {
  224. BuildCtx subctx(ctx);
  225. IHqlExpression * cur = values->queryChild(idx2);
  226. OwnedHqlExpr test = createBoolExpr(no_eq, LINK(lhs), LINK(cur));
  227. OwnedHqlExpr promoted = getExplicitlyPromotedCompare(test);
  228. OwnedHqlExpr subrange, compare, normalized;
  229. extractCompareInformation(subctx, promoted, subrange, compare, normalized, expandedSelector);
  230. //This never changes (it is a function of the lhs), so only evaluate it first time around this loop
  231. if (!boundSubLength.expr)
  232. buildSubRange(ctx, subrange, boundSubLength);
  233. if (compare)
  234. translator.buildFilter(subctx, compare);
  235. OwnedHqlExpr address = getMonitorValueAddress(subctx, expandedSelector, normalized);
  236. HqlExprArray args;
  237. args.append(*LINK(targetVar));
  238. args.append(*LINK(address));
  239. args.append(*LINK(address));
  240. if (boundSubLength.expr)
  241. args.append(*LINK(boundSubLength.expr));
  242. translator.callProcedure(subctx, func, args);
  243. }
  244. }
  245. }
  246. static IHqlExpression * createCompareRecast(node_operator op, IHqlExpression * value, IHqlExpression * recastValue)
  247. {
  248. if (recastValue->queryValue())
  249. return LINK(queryBoolExpr(op == no_ne));
  250. return createValue(op, makeBoolType(), LINK(value), LINK(recastValue));
  251. }
  252. void CppFilterExtractor::extractCompareInformation(BuildCtx & ctx, IHqlExpression * expr, SharedHqlExpr & subrange, SharedHqlExpr & compare, SharedHqlExpr & normalized, IHqlExpression * expandedSelector)
  253. {
  254. extractCompareInformation(ctx, expr->queryChild(0), expr->queryChild(1), subrange, compare, normalized, expandedSelector);
  255. }
  256. void CppFilterExtractor::extractCompareInformation(BuildCtx & ctx, IHqlExpression * lhs, IHqlExpression * value, SharedHqlExpr & subrange, SharedHqlExpr & compare, SharedHqlExpr & normalized, IHqlExpression * expandedSelector)
  257. {
  258. //For substring matching the set of values should match the type of the underlying field.
  259. if (createValueSets)
  260. {
  261. IHqlExpression * base = queryStripCasts(lhs);
  262. if (base->getOperator() == no_substring)
  263. subrange.set(base->queryChild(1));
  264. }
  265. LinkedHqlExpr compareValue = value->queryBody();
  266. OwnedHqlExpr recastValue;
  267. if ((lhs->getOperator() != no_select) || (lhs->queryType() != compareValue->queryType()))
  268. {
  269. OwnedHqlExpr temp = castToFieldAndBack(lhs, compareValue);
  270. if (temp != compareValue)
  271. {
  272. //Force into a temporary variable since it will be used more than once, and reapply the field casting/
  273. compareValue.setown(translator.buildSimplifyExpr(ctx, compareValue));
  274. //cast to promoted type because sometimes evaluating can convert string to string<n>
  275. Owned<ITypeInfo> promotedType = getPromotedECLType(lhs->queryType(), compareValue->queryType());
  276. compareValue.setown(ensureExprType(compareValue, promotedType));
  277. recastValue.setown(castToFieldAndBack(lhs, compareValue));
  278. }
  279. }
  280. normalized.setown(invertTransforms(lhs, compareValue));
  281. normalized.setown(foldHqlExpression(normalized));
  282. if (recastValue && recastValue != compareValue)
  283. compare.setown(createCompareRecast(no_eq, compareValue, recastValue));
  284. }
  285. void CppFilterExtractor::createStringSet(BuildCtx & ctx, const char * target, unsigned size, IHqlExpression * selector)
  286. {
  287. assertex(selector->getOperator() == no_select);
  288. if (createValueSets)
  289. {
  290. StringBuffer type;
  291. translator.buildRtlFieldType(type, selector->queryChild(1), queryRecord(tableExpr));
  292. ctx.addQuotedF("%s.setown(createValueSet(%s));", target, type.str());
  293. }
  294. else
  295. {
  296. if (onlyHozedCompares)
  297. ctx.addQuotedF("%s.setown(createRtlStringSet(%u));", target, size);
  298. else
  299. {
  300. ITypeInfo * type = selector->queryType();
  301. bool isBigEndian = !type->isInteger() || !isLittleEndian(type);
  302. ctx.addQuotedF("%s.setown(createRtlStringSetEx(%u,%d,%d));", target, size, isBigEndian, type->isSigned());
  303. }
  304. }
  305. }
  306. bool CppFilterExtractor::buildSubRange(BuildCtx & ctx, IHqlExpression * range, CHqlBoundExpr & bound)
  307. {
  308. if (!createValueSets)
  309. return false;
  310. if (!range)
  311. return false;
  312. IHqlExpression * limit;
  313. switch (range->getOperator())
  314. {
  315. case no_rangeto:
  316. limit = range->queryChild(0);
  317. break;
  318. case no_range:
  319. assertex(matchesConstValue(range->queryChild(0), 1));
  320. limit = range->queryChild(1);
  321. break;
  322. case no_constant:
  323. limit = range;
  324. assertex(matchesConstValue(range, 1));
  325. break;
  326. default:
  327. throwUnexpected();
  328. }
  329. translator.buildExpr(ctx, limit, bound);
  330. return true;
  331. }
  332. void CppFilterExtractor::buildKeySegmentCompareExpr(BuildFilterState & buildState, KeySelectorInfo & selectorInfo, BuildCtx & ctx, const char * targetSet, IHqlExpression & thisKey)
  333. {
  334. OwnedHqlExpr targetVar = createVariable(targetSet, makeVoidType());
  335. createStringSet(ctx, targetSet, selectorInfo.size, selectorInfo.expandedSelector);
  336. if (!exprReferencesDataset(&thisKey, tableExpr))
  337. {
  338. BuildCtx subctx(ctx);
  339. translator.buildFilter(subctx, &thisKey);
  340. callAddAll(subctx, targetVar);
  341. return;
  342. }
  343. OwnedHqlExpr subrange;
  344. OwnedHqlExpr compare;
  345. OwnedHqlExpr normalized;
  346. BuildCtx subctx(ctx);
  347. extractCompareInformation(subctx, &thisKey, subrange, compare, normalized, selectorInfo.expandedSelector);
  348. OwnedHqlExpr address = getMonitorValueAddress(subctx, selectorInfo.expandedSelector, normalized);
  349. HqlExprArray args;
  350. args.append(*LINK(targetVar));
  351. CHqlBoundExpr boundSubLength;
  352. buildSubRange(ctx, subrange, boundSubLength);
  353. node_operator op = thisKey.getOperator();
  354. switch (op)
  355. {
  356. case no_eq:
  357. if (compare)
  358. translator.buildFilter(subctx, compare);
  359. args.append(*LINK(address));
  360. args.append(*LINK(address));
  361. if (boundSubLength.expr)
  362. args.append(*LINK(boundSubLength.expr));
  363. translator.callProcedure(subctx, addRangeFunc, args);
  364. break;
  365. case no_ne:
  366. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  367. if (compare)
  368. translator.buildFilter(subctx, compare);
  369. args.append(*LINK(address));
  370. args.append(*LINK(address));
  371. if (boundSubLength.expr)
  372. args.append(*LINK(boundSubLength.expr));
  373. translator.callProcedure(subctx, killRangeFunc, args);
  374. break;
  375. case no_le:
  376. args.append(*createValue(no_nullptr, makeVoidType()));
  377. args.append(*LINK(address));
  378. if (boundSubLength.expr)
  379. args.append(*LINK(boundSubLength.expr));
  380. translator.callProcedure(subctx, addRangeFunc, args);
  381. break;
  382. case no_lt:
  383. // e) no_lt. If isExact add < value else add <= value
  384. if (compare)
  385. {
  386. OwnedHqlExpr invCompare = getInverse(compare);
  387. IHqlStmt * cond = translator.buildFilterViaExpr(subctx, invCompare);
  388. //common this up...
  389. args.append(*createValue(no_nullptr, makeVoidType()));
  390. args.append(*LINK(address));
  391. if (boundSubLength.expr)
  392. args.append(*LINK(boundSubLength.expr));
  393. translator.callProcedure(subctx, addRangeFunc, args);
  394. subctx.selectElse(cond);
  395. args.append(*LINK(targetVar));
  396. }
  397. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  398. args.append(*LINK(address));
  399. args.append(*createValue(no_nullptr, makeVoidType()));
  400. if (boundSubLength.expr)
  401. args.append(*LINK(boundSubLength.expr));
  402. translator.callProcedure(subctx, killRangeFunc, args);
  403. break;
  404. case no_ge:
  405. // d) no_ge. If isExact add >= value else add > value
  406. if (compare)
  407. {
  408. OwnedHqlExpr invCompare = getInverse(compare);
  409. IHqlStmt * cond = translator.buildFilterViaExpr(subctx, invCompare);
  410. //common this up...
  411. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  412. args.append(*createValue(no_nullptr, makeVoidType()));
  413. args.append(*LINK(address));
  414. if (boundSubLength.expr)
  415. args.append(*LINK(boundSubLength.expr));
  416. translator.callProcedure(subctx, killRangeFunc, args);
  417. subctx.selectElse(cond);
  418. args.append(*LINK(targetVar));
  419. }
  420. args.append(*LINK(address));
  421. args.append(*createValue(no_nullptr, makeVoidType()));
  422. if (boundSubLength.expr)
  423. args.append(*LINK(boundSubLength.expr));
  424. translator.callProcedure(subctx, addRangeFunc, args);
  425. break;
  426. case no_gt:
  427. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  428. args.append(*createValue(no_nullptr, makeVoidType()));
  429. args.append(*LINK(address));
  430. if (boundSubLength.expr)
  431. args.append(*LINK(boundSubLength.expr));
  432. translator.callProcedure(subctx, killRangeFunc, args);
  433. break;
  434. case no_between:
  435. case no_notbetween:
  436. {
  437. //NB: This should only be generated for substring queries. User betweens are converted
  438. //to two separate comparisons to cope with range issues.
  439. args.append(*LINK(address));
  440. CHqlBoundExpr rhs2;
  441. OwnedHqlExpr adjustedUpper = invertTransforms(thisKey.queryChild(0), thisKey.queryChild(2));
  442. OwnedHqlExpr foldedUpper = foldHqlExpression(adjustedUpper);
  443. OwnedHqlExpr hozedValue = getHozedKeyValue(foldedUpper);
  444. IIdAtom * name = hozedValue->queryId();
  445. if ((name != createRangeHighId) && (name != createQStrRangeHighId))
  446. hozedValue.setown(ensureExprType(hozedValue, selectorInfo.expandedSelector->queryType()));
  447. translator.buildExpr(subctx, hozedValue, rhs2);
  448. translator.ensureHasAddress(subctx, rhs2);
  449. args.append(*getPointer(rhs2.expr));
  450. if (op == no_between)
  451. {
  452. if (boundSubLength.expr)
  453. args.append(*LINK(boundSubLength.expr));
  454. translator.callProcedure(subctx, addRangeFunc, args);
  455. }
  456. else
  457. {
  458. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  459. if (boundSubLength.expr)
  460. args.append(*LINK(boundSubLength.expr));
  461. translator.callProcedure(subctx, killRangeFunc, args);
  462. }
  463. break;
  464. }
  465. default:
  466. throwUnexpectedOp(op);
  467. }
  468. }
  469. //Note this function may change the incoming ctx if filterKind is not NoMonitorFilter
  470. void CppFilterExtractor::buildKeySegmentExpr(BuildFilterState & buildState, KeySelectorInfo & selectorInfo, BuildCtx & ctx, const char * requiredSet, IHqlExpression & thisKey, MonitorFilterKind filterKind)
  471. {
  472. const char * targetSet = requiredSet;
  473. StringBuffer s;
  474. unsigned curSize = selectorInfo.size;
  475. node_operator op = thisKey.getOperator();
  476. BuildCtx subctx(ctx);
  477. BuildCtx * appendCtx = &ctx;
  478. StringBuffer createMonitorText;
  479. switch (op)
  480. {
  481. case no_in:
  482. case no_notin:
  483. {
  484. if (!targetSet)
  485. targetSet = buildState.getSetName(createValueSets);
  486. buildKeySegmentInExpr(buildState, selectorInfo, ctx, targetSet, thisKey, filterKind);
  487. break;
  488. }
  489. case no_if:
  490. {
  491. MonitorFilterKind childFilter = targetSet ? NoMonitorFilter : filterKind;
  492. IHqlStmt * ifStmt = translator.buildFilterViaExpr(subctx, thisKey.queryChild(0));
  493. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, *thisKey.queryChild(1), childFilter);
  494. subctx.selectElse(ifStmt);
  495. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, *thisKey.queryChild(2), childFilter);
  496. break;
  497. }
  498. case no_and:
  499. {
  500. HqlExprArray matches;
  501. OwnedHqlExpr invariant = unwindConjunction(matches, &thisKey);
  502. unsigned numMatches = matches.ordinality();
  503. if (!targetSet && numMatches > 1)
  504. targetSet = buildState.getSetName(createValueSets);
  505. IHqlStmt * ifStmt = NULL;
  506. if (invariant)
  507. {
  508. ifStmt = translator.buildFilterViaExpr(subctx, invariant);
  509. if (filterKind == MonitorFilterSkipEmpty)
  510. ctx.set(subctx);
  511. }
  512. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, matches.item(0), NoMonitorFilter);
  513. for (unsigned i=1; i< numMatches; i++)
  514. {
  515. IHqlExpression & cur = matches.item(i);
  516. const char * curTarget = buildState.getSetName(createValueSets);
  517. BuildCtx childctx(subctx);
  518. buildKeySegmentExpr(buildState, selectorInfo, childctx, curTarget, cur, MonitorFilterSkipAll);
  519. if (createValueSets)
  520. childctx.addQuotedF("%s->intersectSet(%s);", targetSet, curTarget);
  521. else
  522. childctx.addQuotedF("%s.setown(rtlIntersectSet(%s,%s));", targetSet, targetSet, curTarget);
  523. buildState.popSetName();
  524. }
  525. if (invariant && (filterKind != MonitorFilterSkipEmpty))
  526. {
  527. subctx.selectElse(ifStmt);
  528. if (targetSet)
  529. createStringSet(subctx, targetSet, curSize, selectorInfo.selector);
  530. else
  531. buildEmptyKeySegment(buildState, subctx, selectorInfo);
  532. }
  533. break;
  534. }
  535. case no_or:
  536. {
  537. HqlExprArray matches;
  538. OwnedHqlExpr invariant = unwindConjunction(matches, &thisKey);
  539. unsigned numMatches = matches.ordinality();
  540. if (invariant)
  541. {
  542. if (filterKind == MonitorFilterSkipAll)
  543. {
  544. OwnedHqlExpr test = getInverse(invariant);
  545. translator.buildFilter(subctx, test);
  546. ctx.set(subctx);
  547. }
  548. else
  549. {
  550. IHqlStmt * ifStmt = translator.buildFilterViaExpr(subctx, invariant);
  551. if (targetSet)
  552. {
  553. createStringSet(subctx, targetSet, curSize, selectorInfo.selector);
  554. OwnedHqlExpr targetVar = createVariable(targetSet, makeVoidType());
  555. callAddAll(subctx, targetVar);
  556. }
  557. subctx.selectElse(ifStmt);
  558. }
  559. }
  560. appendCtx = &subctx;
  561. if (!targetSet && numMatches > 1)
  562. targetSet = buildState.getSetName(createValueSets);
  563. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, matches.item(0), NoMonitorFilter);
  564. for (unsigned i=1; i < numMatches; i++)
  565. {
  566. IHqlExpression & cur = matches.item(i);
  567. const char * curTarget = buildState.getSetName(createValueSets);
  568. BuildCtx childctx(subctx);
  569. buildKeySegmentExpr(buildState, selectorInfo, childctx, curTarget, cur, MonitorFilterSkipEmpty);
  570. if (createValueSets)
  571. childctx.addQuotedF("%s->unionSet(%s);", targetSet, curTarget);
  572. else
  573. childctx.addQuotedF("%s.setown(rtlUnionSet(%s, %s));", targetSet, targetSet, curTarget);
  574. buildState.popSetName();
  575. }
  576. break;
  577. }
  578. case no_eq:
  579. {
  580. if (!targetSet)
  581. {
  582. if (buildSingleKeyMonitor(createMonitorText, selectorInfo, subctx, thisKey))
  583. break;
  584. targetSet = buildState.getSetName(createValueSets);
  585. }
  586. buildKeySegmentCompareExpr(buildState, selectorInfo, ctx, targetSet, thisKey);
  587. break;
  588. }
  589. default:
  590. {
  591. if (!targetSet)
  592. targetSet = buildState.getSetName(createValueSets);
  593. buildKeySegmentCompareExpr(buildState, selectorInfo, ctx, targetSet, thisKey);
  594. break;
  595. }
  596. }
  597. if (targetSet && !requiredSet)
  598. {
  599. if (createValueSets)
  600. createMonitorText.appendf("createFieldFilter(%u, %s)", selectorInfo.fieldIdx, targetSet);
  601. else
  602. createMonitorText.appendf("createKeySegmentMonitor(%s, %s.getClear(), %u, %u, %u)",
  603. boolToText(selectorInfo.keyedKind != KeyedYes), targetSet, selectorInfo.fieldIdx, selectorInfo.offset, selectorInfo.size);
  604. buildState.popSetName();
  605. }
  606. if (createMonitorText.length())
  607. {
  608. if (buildState.listName)
  609. {
  610. if (createValueSets)
  611. appendCtx->addQuotedF("%s->append(%s, %s);", buildState.listName, selectorInfo.getFFOptions(), createMonitorText.str());
  612. else
  613. appendCtx->addQuotedF("%s->append(%s);", buildState.listName, createMonitorText.str());
  614. }
  615. else
  616. appendCtx->addQuotedF("return %s;", createMonitorText.str());
  617. }
  618. }
  619. IHqlExpression * CppFilterExtractor::getMonitorValueAddress(BuildCtx & ctx, IHqlExpression * selector, IHqlExpression * _value)
  620. {
  621. LinkedHqlExpr value = _value;
  622. CHqlBoundExpr bound;
  623. ITypeInfo * type = selector->queryType();
  624. bool castViaRow = isUnknownSize(type);
  625. if (castViaRow)
  626. {
  627. IHqlExpression * field = selector->queryChild(1);
  628. OwnedHqlExpr record = createRecord(field);
  629. OwnedHqlExpr self = createSelector(no_self, record, nullptr);
  630. OwnedHqlExpr assign = createValue(no_assign, makeVoidType(), createNewSelectExpr(LINK(self), LINK(field)), LINK(value));
  631. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(record->getType()), LINK(assign));
  632. OwnedHqlExpr row = createRow(no_createrow, LINK(transform));
  633. translator.buildAnyExpr(ctx, row, bound);
  634. }
  635. else
  636. {
  637. if (!createValueSets)
  638. {
  639. //Need to ensure old segmonitors for varstrings are filled with \0s
  640. switch (type->getTypeCode())
  641. {
  642. case type_varstring: case type_varunicode:
  643. {
  644. assertex(type->getSize() != UNKNOWN_LENGTH);
  645. CHqlBoundTarget tempTarget;
  646. translator.createTempFor(ctx, type, tempTarget, typemod_none, FormatNatural);
  647. //clear the variable.
  648. HqlExprArray args;
  649. args.append(*getPointer(tempTarget.expr));
  650. args.append(*getZero());
  651. args.append(*getSizetConstant(type->getSize()));
  652. OwnedHqlExpr call = translator.bindTranslatedFunctionCall(memsetId, args);
  653. ctx.addExpr(call);
  654. //then assign over the top
  655. translator.buildExprAssign(ctx, tempTarget, value);
  656. bound.setFromTarget(tempTarget);
  657. break;
  658. }
  659. }
  660. }
  661. if (!bound.expr)
  662. {
  663. translator.buildExpr(ctx, value, bound);
  664. translator.ensureHasAddress(ctx, bound);
  665. }
  666. }
  667. return getPointer(bound.expr);
  668. }
  669. bool CppFilterExtractor::buildSingleKeyMonitor(StringBuffer & createMonitorText, KeySelectorInfo & selectorInfo, BuildCtx & ctx, IHqlExpression & thisKey)
  670. {
  671. if (selectorInfo.subrange)
  672. return false;
  673. BuildCtx subctx(ctx);
  674. OwnedHqlExpr subrange, compare, normalized;
  675. StringBuffer funcName;
  676. extractCompareInformation(subctx, &thisKey, subrange, compare, normalized, selectorInfo.expandedSelector);
  677. if (compare || subrange)
  678. return false;
  679. if (createValueSets)
  680. {
  681. StringBuffer type;
  682. translator.buildRtlFieldType(type, selectorInfo.selector->queryChild(1), tableExpr->queryRecord());
  683. //MORE: Need to ensure it is exactly the correct format - e.g. variable length strings are length prefixed
  684. OwnedHqlExpr address = getMonitorValueAddress(subctx, selectorInfo.expandedSelector, normalized);
  685. StringBuffer addrText;
  686. translator.generateExprCpp(addrText, address);
  687. createMonitorText.appendf("createFieldFilter(%u, %s, %s)", selectorInfo.fieldIdx, type.str(), addrText.str());
  688. }
  689. else
  690. {
  691. ITypeInfo * type = selectorInfo.expandedSelector->queryType();
  692. type_t tc = type->getTypeCode();
  693. if ((tc == type_int) || (tc == type_swapint))
  694. {
  695. if (isLittleEndian(type))
  696. {
  697. if (type->isSigned())
  698. funcName.append("createSingleLittleSignedKeySegmentMonitor");
  699. else if (type->getSize() != 1)
  700. funcName.append("createSingleLittleKeySegmentMonitor");
  701. }
  702. else
  703. {
  704. if (type->isSigned())
  705. funcName.append("createSingleBigSignedKeySegmentMonitor");
  706. else
  707. funcName.append("createSingleKeySegmentMonitor");
  708. }
  709. }
  710. if (!funcName.length())
  711. funcName.append("createSingleKeySegmentMonitor");
  712. OwnedHqlExpr address = getMonitorValueAddress(subctx, selectorInfo.expandedSelector, normalized);
  713. StringBuffer addrText;
  714. translator.generateExprCpp(addrText, address);
  715. createMonitorText.append(funcName)
  716. .appendf("(%s, %u, %u, %u, %s)",
  717. boolToText(selectorInfo.keyedKind != KeyedYes), selectorInfo.fieldIdx, selectorInfo.offset, selectorInfo.size, addrText.str());
  718. }
  719. return true;
  720. }
  721. KeyedKind getKeyedKind(HqlCppTranslator & translator, KeyConditionArray & matches)
  722. {
  723. KeyedKind keyedKind = KeyedNo;
  724. ForEachItemIn(i, matches)
  725. {
  726. KeyCondition & cur = matches.item(i);
  727. if (cur.keyedKind != keyedKind)
  728. {
  729. if (keyedKind == KeyedNo)
  730. keyedKind = cur.keyedKind;
  731. else
  732. translator.throwError1(HQLERR_InconsistentKeyedOpt, str(cur.selector->queryChild(1)->queryName()));
  733. }
  734. }
  735. return keyedKind;
  736. }
  737. void CppFilterExtractor::buildEmptyKeySegment(BuildFilterState & buildState, BuildCtx & ctx, KeySelectorInfo & selectorInfo)
  738. {
  739. StringBuffer s;
  740. if (createValueSets)
  741. {
  742. StringBuffer type;
  743. translator.buildRtlFieldType(type, selectorInfo.selector->queryChild(1), queryRecord(selectorInfo.selector->queryChild(0)));
  744. ctx.addQuoted(s.appendf("%s->append(%s, createEmptyFieldFilter(%u, %s));", buildState.listName, selectorInfo.getFFOptions(), selectorInfo.fieldIdx, type.str()));
  745. }
  746. else
  747. ctx.addQuoted(s.appendf("%s->append(createEmptyKeySegmentMonitor(%s, %u, %u, %u));", buildState.listName, boolToText(selectorInfo.keyedKind != KeyedYes), selectorInfo.fieldIdx, selectorInfo.offset, selectorInfo.size));
  748. }
  749. void CppFilterExtractor::buildKeySegment(BuildFilterState & buildState, BuildCtx & ctx, unsigned whichField, unsigned curSize)
  750. {
  751. IHqlExpression * selector = &keyableSelects.item(whichField);
  752. IHqlExpression * expandedSelector = &expandedSelects.item(whichField);
  753. IHqlExpression * field = selector->queryChild(1);
  754. KeyConditionArray matches;
  755. bool isImplicit = true;
  756. bool prevWildWasKeyed = buildState.wildWasKeyed;
  757. buildState.wildWasKeyed = false;
  758. ForEachItemIn(cond, keyed.conditions)
  759. {
  760. KeyCondition & cur = keyed.conditions.item(cond);
  761. if (cur.selector == selector)
  762. {
  763. cur.generated = true;
  764. if (cur.isWild)
  765. {
  766. isImplicit = false;
  767. if (cur.wasKeyed)
  768. buildState.wildWasKeyed = true;
  769. else if (buildState.implicitWildField && !ignoreUnkeyed)
  770. {
  771. StringBuffer s, keyname;
  772. translator.throwError3(HQLERR_WildFollowsGap, getExprECL(field, s).str(), str(buildState.implicitWildField->queryChild(1)->queryName()), queryKeyName(keyname));
  773. }
  774. }
  775. else
  776. {
  777. matches.append(OLINK(cur));
  778. if (buildState.implicitWildField && !ignoreUnkeyed)
  779. {
  780. StringBuffer s,keyname;
  781. if (cur.isKeyed())
  782. translator.throwError3(HQLERR_KeyedFollowsGap, getExprECL(field, s).str(), str(buildState.implicitWildField->queryChild(1)->queryName()), queryKeyName(keyname));
  783. else if (!buildState.doneImplicitWarning)
  784. {
  785. translator.WARNING3(CategoryEfficiency, HQLWRN_KeyedFollowsGap, getExprECL(field, s).str(), str(buildState.implicitWildField->queryChild(1)->queryName()), queryKeyName(keyname));
  786. buildState.doneImplicitWarning = true;
  787. }
  788. }
  789. }
  790. }
  791. }
  792. if (buildState.wildWasKeyed && (matches.ordinality() == 0))
  793. {
  794. StringBuffer keyname;
  795. translator.WARNING2(CategoryFolding, HQLWRN_FoldRemoveKeyed, str(field->queryName()), queryKeyName(keyname));
  796. }
  797. StringBuffer s;
  798. KeyedKind keyedKind = getKeyedKind(translator, matches);
  799. if (whichField >= firstOffsetField)
  800. translator.throwError1(HQLERR_KeyedNotKeyed, getExprECL(field, s).str());
  801. KeySelectorInfo selectorInfo(keyedKind, selector, nullptr, expandedSelector, buildState.curFieldIdx, buildState.curOffset, curSize);
  802. bool ignoreKeyedExtend = false;
  803. if ((keyedKind == KeyedExtend) && buildState.wildPending() && !ignoreUnkeyed)
  804. {
  805. if (keyedKind == KeyedExtend)
  806. {
  807. if (prevWildWasKeyed)
  808. buildState.wildWasKeyed = true;
  809. else
  810. {
  811. StringBuffer keyname;
  812. translator.WARNING2(CategoryEfficiency, HQLERR_OptKeyedFollowsWild, getExprECL(field, s).str(), queryKeyName(keyname));
  813. }
  814. }
  815. //previous condition folded so always true, so keyed,opt will always be a wildcard.
  816. if (!allowDynamicFormatChange)
  817. ignoreKeyedExtend = true;
  818. isImplicit = false;
  819. }
  820. if (matches.ordinality() && !ignoreKeyedExtend)
  821. {
  822. if (buildState.wildPending() && !ignoreUnkeyed)
  823. buildState.clearWild();
  824. HqlExprArray args;
  825. ForEachItemIn(i, matches)
  826. {
  827. KeyCondition & cur = matches.item(i);
  828. args.append(*LINK(cur.expr));
  829. }
  830. OwnedHqlExpr fullExpr = createBalanced(no_and, queryBoolType(), args);
  831. BuildCtx subctx(ctx);
  832. buildKeySegmentExpr(buildState, selectorInfo, subctx, NULL, *fullExpr, ignoreUnkeyed ? MonitorFilterSkipAll : NoMonitorFilter);
  833. }
  834. else
  835. {
  836. if (isImplicit)
  837. {
  838. buildState.implicitWildField.set(selector);
  839. buildState.doneImplicitWarning = false;
  840. }
  841. if (buildState.wildPending() && noMergeSelects.contains(*selector))
  842. buildState.clearWild();
  843. if (!buildState.wildPending())
  844. buildState.wildOffset = buildState.curOffset;
  845. }
  846. buildState.curOffset += selectorInfo.size;
  847. buildState.curFieldIdx++;
  848. }
  849. void CppFilterExtractor::spotSegmentCSE(BuildCtx & ctx)
  850. {
  851. //This could make things much better, but needs some thought
  852. HqlExprArray conditions;
  853. ForEachItemIn(cond, keyed.conditions)
  854. {
  855. KeyCondition & cur = keyed.conditions.item(cond);
  856. if (cur.expr)
  857. conditions.append(*LINK(cur.expr));
  858. }
  859. HqlExprArray associated;
  860. IHqlExpression * selector = tableExpr->queryNormalizedSelector();
  861. translator.traceExpressions("before seg spot", conditions);
  862. spotScalarCSE(conditions, associated, NULL, selector, translator.queryOptions().spotCseInIfDatasetConditions);
  863. translator.traceExpressions("after seg spot", conditions);
  864. unsigned curCond = 0;
  865. ForEachItemIn(i, conditions)
  866. {
  867. IHqlExpression * cur = &conditions.item(i);
  868. switch (cur->getOperator())
  869. {
  870. case no_alias:
  871. translator.buildStmt(ctx, cur);
  872. break;
  873. case no_alias_scope:
  874. translator.expandAliasScope(ctx, cur);
  875. cur = cur->queryChild(0);
  876. //fallthrough
  877. default:
  878. for (;;)
  879. {
  880. if (!keyed.conditions.isItem(curCond))
  881. throwUnexpected();
  882. KeyCondition & keyCond = keyed.conditions.item(curCond++);
  883. if (keyCond.expr)
  884. {
  885. keyCond.expr.set(cur);
  886. break;
  887. }
  888. }
  889. break;
  890. }
  891. }
  892. for (;;)
  893. {
  894. if (!keyed.conditions.isItem(curCond))
  895. break;
  896. KeyCondition & keyCond = keyed.conditions.item(curCond++);
  897. assertex(!keyCond.expr);
  898. }
  899. }
  900. void CppFilterExtractor::buildSegments(BuildCtx & ctx, const char * listName, bool _ignoreUnkeyed)
  901. {
  902. translator.useInclude("rtlkey.hpp");
  903. ignoreUnkeyed = _ignoreUnkeyed;
  904. if (translator.queryOptions().spotCSE)
  905. spotSegmentCSE(ctx);
  906. BuildFilterState buildState(ctx, listName);
  907. ForEachItemIn(idx, keyableSelects)
  908. {
  909. IHqlExpression * selector = &keyableSelects.item(idx);
  910. IHqlExpression * expandedSelector = &expandedSelects.item(idx);
  911. IHqlExpression * field = selector->queryChild(1);
  912. unsigned curSize = expandedSelector->queryType()->getSize();
  913. assertex(createValueSets || curSize != UNKNOWN_LENGTH);
  914. //MORE: Should also allow nested record structures, and allow keying on first elements.
  915. // and field->queryType()->getSize() doesn't work for alien datatypes etc.
  916. if(!field->hasAttribute(virtualAtom))
  917. buildKeySegment(buildState, ctx, idx, curSize);
  918. }
  919. //check that all keyed entries have been matched
  920. ForEachItemIn(cond, keyed.conditions)
  921. {
  922. KeyCondition & cur = keyed.conditions.item(cond);
  923. if (!cur.generated)
  924. translator.throwError1(HQLERR_OnlyKeyFixedField, str(cur.selector->queryChild(1)->queryId()));
  925. }
  926. }
  927. IHqlExpression * CppFilterExtractor::getRangeLimit(ITypeInfo * fieldType, IHqlExpression * lengthExpr, IHqlExpression * value, int whichBoundary)
  928. {
  929. IHqlExpression * constExpr = FilterExtractor::getRangeLimit(fieldType, lengthExpr, value, whichBoundary);
  930. if (constExpr)
  931. return constExpr;
  932. type_t ftc = fieldType->getTypeCode();
  933. unsigned fieldLength = fieldType->getStringLen();
  934. IIdAtom * func;
  935. if (whichBoundary < 0)
  936. {
  937. switch (ftc)
  938. {
  939. case type_qstring:
  940. func = createQStrRangeLowId;
  941. break;
  942. case type_string:
  943. func = createStrRangeLowId;
  944. break;
  945. case type_data:
  946. func = createDataRangeLowId;
  947. break;
  948. case type_unicode:
  949. func = createUnicodeRangeLowId;
  950. break;
  951. default:
  952. func = createRangeLowId;
  953. break;
  954. }
  955. }
  956. else
  957. {
  958. switch (ftc)
  959. {
  960. case type_qstring:
  961. func = createQStrRangeHighId;
  962. break;
  963. case type_string:
  964. func = createStrRangeHighId;
  965. break;
  966. case type_data:
  967. func = createDataRangeHighId;
  968. break;
  969. case type_unicode:
  970. func = createUnicodeRangeHighId;
  971. break;
  972. default:
  973. func = createRangeHighId;
  974. break;
  975. }
  976. }
  977. HqlExprArray args;
  978. args.append(*getSizetConstant(fieldLength));
  979. args.append(*LINK(lengthExpr));
  980. args.append(*LINK(value));
  981. //Note: I can't change the return type of the function - because if fixed length then wrong call is made, and variable length is worse code.
  982. OwnedHqlExpr call = translator.bindFunctionCall(func, args);
  983. return createValue(no_typetransfer, LINK(fieldType), LINK(call));
  984. }
  985. static HqlTransformerInfo selectSpotterInfo("SelectSpotter");
  986. CppFilterExtractor::SelectSpotter::SelectSpotter(const HqlExprArray & _selects) : NewHqlTransformer(selectSpotterInfo), selects(_selects)
  987. {
  988. hasSelects = false;
  989. }
  990. void CppFilterExtractor::SelectSpotter::analyseExpr(IHqlExpression * expr)
  991. {
  992. if (hasSelects || alreadyVisited(expr))
  993. return;
  994. if (selects.find(*expr) != NotFound)
  995. {
  996. hasSelects = true;
  997. return;
  998. }
  999. NewHqlTransformer::analyseExpr(expr);
  1000. }