hqlcfilter.cpp 40 KB

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