hqlcpputil.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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 "platform.h"
  14. #include "jlib.hpp"
  15. #include "jexcept.hpp"
  16. #include "jmisc.hpp"
  17. #include "workunit.hpp"
  18. #include "hql.hpp"
  19. #include "hqlexpr.hpp"
  20. #include "hqlfold.hpp"
  21. #include "hqlstmt.hpp"
  22. #include "hqltrans.ipp"
  23. #include "hqlutil.hpp"
  24. #include "hqlattr.hpp"
  25. #include "hqlcatom.hpp"
  26. #include "hqlfunc.hpp"
  27. #include "hqlcpp.ipp"
  28. #include "hqlcpputil.hpp"
  29. //===========================================================================
  30. static ITypeInfo * cachedVoidType;
  31. static IHqlExpression * cachedZero;
  32. static IHqlExpression * cachedNullChar;
  33. static IHqlExpression * defaultAttrExpr;
  34. static IHqlExpression * selfAttrExpr;
  35. ITypeInfo * boolType;
  36. ITypeInfo * sizetType;
  37. ITypeInfo * signedType;
  38. ITypeInfo * unsignedType;
  39. ITypeInfo * defaultIntegralType;
  40. ITypeInfo * counterType;
  41. ITypeInfo * unknownDataType;
  42. ITypeInfo * unknownStringType;
  43. ITypeInfo * unknownVarStringType;
  44. ITypeInfo * unknownUtf8Type;
  45. ITypeInfo * constUnknownVarStringType;
  46. ITypeInfo * unknownUnicodeType;
  47. ITypeInfo * fposType;
  48. ITypeInfo * doubleType;
  49. IHqlExpression * skipActionMarker;
  50. IHqlExpression * skipReturnMarker;
  51. IHqlExpression * subGraphMarker;
  52. IHqlExpression * removedAssignTag;
  53. IHqlExpression * internalAttrExpr;
  54. IHqlExpression * activityIdMarkerExpr;
  55. IHqlExpression * conditionalRowMarkerExpr;
  56. //===========================================================================
  57. MODULE_INIT(INIT_PRIORITY_STANDARD)
  58. {
  59. boolType = makeBoolType();
  60. signedType = makeIntType(sizeof(signed), true);
  61. unsignedType = makeIntType(sizeof(unsigned), false);
  62. sizetType = makeIntType(sizeof(size32_t), false);
  63. defaultIntegralType = makeIntType(8, true);
  64. counterType = makeIntType(8, false);
  65. unknownDataType = makeDataType(UNKNOWN_LENGTH);
  66. unknownStringType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  67. unknownVarStringType = makeVarStringType(UNKNOWN_LENGTH);
  68. unknownUtf8Type = makeUtf8Type(UNKNOWN_LENGTH, 0);
  69. constUnknownVarStringType = makeConstantModifier(LINK(unknownVarStringType));
  70. unknownUnicodeType = makeUnicodeType(UNKNOWN_LENGTH, 0);
  71. fposType = makeIntType(8, false);
  72. doubleType = makeRealType(8);
  73. cachedVoidType = makeVoidType();
  74. cachedZero = createIntConstant(0);
  75. cachedNullChar = createConstant(createCharValue(0, makeCharType()));
  76. defaultAttrExpr = createAttribute(defaultAtom);
  77. selfAttrExpr = createAttribute(selfAtom);
  78. skipActionMarker = createAttribute(skipActionMarkerAtom);
  79. skipReturnMarker = createAttribute(skipReturnMarkerAtom);
  80. subGraphMarker = createAttribute(subgraphAtom);
  81. removedAssignTag = createAttribute(_internal_Atom);
  82. internalAttrExpr = createAttribute(internalAtom);
  83. activityIdMarkerExpr = createAttribute(activityIdMarkerAtom);
  84. conditionalRowMarkerExpr = createAttribute(_conditionalRowMarker_Atom);
  85. return true;
  86. }
  87. MODULE_EXIT()
  88. {
  89. conditionalRowMarkerExpr->Release();
  90. activityIdMarkerExpr->Release();
  91. internalAttrExpr->Release();
  92. removedAssignTag->Release();
  93. subGraphMarker->Release();
  94. skipReturnMarker->Release();
  95. skipActionMarker->Release();
  96. selfAttrExpr->Release();
  97. defaultAttrExpr->Release();
  98. boolType->Release();
  99. cachedVoidType->Release();
  100. cachedZero->Release();
  101. cachedNullChar->Release();
  102. unsignedType->Release();
  103. signedType->Release();
  104. defaultIntegralType->Release();
  105. sizetType->Release();
  106. counterType->Release();
  107. unknownDataType->Release();
  108. unknownStringType->Release();
  109. unknownVarStringType->Release();
  110. unknownUtf8Type->Release();
  111. constUnknownVarStringType->Release();
  112. unknownUnicodeType->Release();
  113. fposType->Release();
  114. doubleType->Release();
  115. }
  116. //===========================================================================
  117. IHqlExpression * getZero() { return LINK(cachedZero); }
  118. ITypeInfo * queryBoolType() { return boolType; }
  119. ITypeInfo * queryVoidType() { return cachedVoidType; }
  120. IHqlExpression * queryNullChar() { return cachedNullChar; }
  121. IHqlExpression * queryZero() { return cachedZero; }
  122. IHqlExpression * getDefaultAttr() { return LINK(defaultAttrExpr); }
  123. IHqlExpression * getSelfAttr() { return LINK(selfAttrExpr); }
  124. IHqlExpression * queryActivityIdMarker() { return activityIdMarkerExpr; }
  125. IHqlExpression * queryConditionalRowMarker() { return conditionalRowMarkerExpr; }
  126. //===========================================================================
  127. ITypeInfo * getArrayElementType(ITypeInfo * itemType)
  128. {
  129. // use a var string type to get better C++ generated...
  130. if (storePointerInArray(itemType))
  131. return makeVarStringType(UNKNOWN_LENGTH);
  132. return LINK(itemType);
  133. }
  134. ITypeInfo * getConcatResultType(IHqlExpression * expr)
  135. {
  136. assertex(!"not sure if this is unicode safe, but appears not to be used");
  137. //first work out the maximum size of the target
  138. unsigned max = expr->numChildren();
  139. unsigned idx;
  140. unsigned totalSize = 0;
  141. bool unknown = false;
  142. type_t resultType = type_string;
  143. for (idx = 0; idx < max; idx++)
  144. {
  145. ITypeInfo * type = expr->queryChild(idx)->queryType();
  146. unsigned size = type->getStringLen();
  147. if (size == UNKNOWN_LENGTH)
  148. unknown = true;
  149. else
  150. totalSize += size;
  151. if (type->getTypeCode() == type_varstring)
  152. resultType = type_varstring;
  153. }
  154. if (unknown)
  155. totalSize = 1023;
  156. if (resultType == type_string)
  157. return makeStringType(totalSize, NULL, NULL);
  158. return makeVarStringType(totalSize);
  159. }
  160. bool isCompare3Valued(ITypeInfo * type)
  161. {
  162. type = type->queryPromotedType();
  163. switch (type->getTypeCode())
  164. {
  165. case type_string: case type_data:
  166. if (type->getSize() != 1)
  167. return true;
  168. break;
  169. case type_qstring:
  170. case type_varstring:
  171. case type_unicode:
  172. case type_varunicode:
  173. case type_decimal:
  174. case type_utf8:
  175. return true;
  176. }
  177. return false;
  178. }
  179. bool storePointerInArray(ITypeInfo * type)
  180. {
  181. return type->isReference() && isTypePassedByAddress(type);
  182. }
  183. //---------------------------------------------------------------------------
  184. bool isSelectSortedTop(IHqlExpression * selectExpr)
  185. {
  186. IHqlExpression * index = selectExpr->queryChild(1);
  187. if (matchesConstantValue(index, 1))
  188. {
  189. IHqlExpression * ds = selectExpr->queryChild(0);
  190. return ((ds->getOperator() == no_sort) || (ds->getOperator() == no_topn));
  191. }
  192. return false;
  193. }
  194. //---------------------------------------------------------------------------
  195. ITypeInfo * makeRowReferenceType(IHqlExpression * ds)
  196. {
  197. ITypeInfo * recordType = ds ? LINK(ds->queryRecordType()) : NULL;
  198. ITypeInfo * rowType = makeReferenceModifier(makeRowType(recordType));
  199. if (ds)
  200. {
  201. ITypeInfo * dsType = ds->queryType();
  202. if (hasLinkedRow(dsType))
  203. rowType = makeAttributeModifier(rowType, getLinkCountedAttr());
  204. if (hasOutOfLineModifier(dsType))
  205. rowType = makeOutOfLineModifier(rowType);
  206. }
  207. return rowType;
  208. }
  209. ITypeInfo * makeRowReferenceType(const CHqlBoundExpr & bound)
  210. {
  211. return makeRowReferenceType(bound.expr);
  212. }
  213. IHqlExpression * addMemberSelector(IHqlExpression * expr, IHqlExpression * selector)
  214. {
  215. if (!expr)
  216. return NULL;
  217. if (expr->getOperator() == no_variable)
  218. return createValue(no_pselect, expr->getType(), LINK(selector), LINK(expr));
  219. if (expr->numChildren() == 0)
  220. return LINK(expr);
  221. HqlExprArray args;
  222. ForEachChild(i, expr)
  223. args.append(*addMemberSelector(expr->queryChild(i), selector));
  224. return expr->clone(args);
  225. }
  226. //Only called on translated expressions
  227. IHqlExpression * addExpressionModifier(IHqlExpression * expr, typemod_t modifier, IInterface * extra)
  228. {
  229. //Not sure which is best implementation...
  230. #if 1
  231. return createValue(no_typetransfer, makeModifier(expr->getType(), modifier, LINK(extra)), LINK(expr));
  232. #else
  233. HqlExprArray args;
  234. unwindChildren(args, expr);
  235. return createValue(expr->getOperator(), makeModifier(expr->getType(), modifier, LINK(extra)), args);
  236. #endif
  237. }
  238. static void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, StringBuffer & prefix, const char * sep, IHqlExpression * formatFunc)
  239. {
  240. ForEachChild(i, record)
  241. {
  242. IHqlExpression * cur = record->queryChild(i);
  243. switch (cur->getOperator())
  244. {
  245. case no_record:
  246. expandFieldNames(errorProcessor, out, cur, prefix, sep, formatFunc);
  247. break;
  248. case no_ifblock:
  249. expandFieldNames(errorProcessor, out, cur->queryChild(1), prefix, sep, formatFunc);
  250. break;
  251. case no_field:
  252. {
  253. StringBuffer lowerName;
  254. lowerName.append(cur->queryName()).toLowerCase();
  255. if (formatFunc)
  256. {
  257. HqlExprArray args;
  258. args.append(*createConstant(lowerName.str()));
  259. OwnedHqlExpr bound = createBoundFunction(NULL, formatFunc, args, NULL, true);
  260. OwnedHqlExpr folded = foldHqlExpression(errorProcessor, bound, NULL, HFOthrowerror|HFOfoldimpure|HFOforcefold);
  261. assertex(folded->queryValue());
  262. lowerName.clear();
  263. getStringValue(lowerName, folded);
  264. }
  265. switch (cur->queryType()->getTypeCode())
  266. {
  267. case type_record:
  268. case type_row:
  269. {
  270. unsigned len = prefix.length();
  271. prefix.append(lowerName).append(".");
  272. expandFieldNames(errorProcessor, out, cur->queryRecord(), prefix, sep, formatFunc);
  273. prefix.setLength(len);
  274. break;
  275. }
  276. default:
  277. {
  278. if (out.length())
  279. out.append(sep);
  280. out.append(prefix).append(lowerName);
  281. break;
  282. }
  283. }
  284. break;
  285. }
  286. }
  287. }
  288. }
  289. void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, const char * sep, IHqlExpression * formatFunc)
  290. {
  291. StringBuffer prefix;
  292. expandFieldNames(errorProcessor, out, record, prefix, sep, formatFunc);
  293. }
  294. IHqlExpression * ensurePositiveOrZeroInt64(IHqlExpression * expr)
  295. {
  296. if (!expr->queryType()->isSigned())
  297. return LINK(expr);
  298. Owned<ITypeInfo> type = makeIntType(8, true);
  299. if (isCast(expr) && expr->queryType() == type)
  300. {
  301. ITypeInfo * uncastType = expr->queryChild(0)->queryType();
  302. if (!uncastType->isSigned() && uncastType->isInteger() && uncastType->getSize() < 8)
  303. return LINK(expr);
  304. }
  305. OwnedHqlExpr cast = ensureExprType(expr, type);
  306. IValue * value = cast->queryValue();
  307. Owned<IValue> zeroValue = type->castFrom(true, I64C(0));
  308. OwnedHqlExpr zero = createConstant(LINK(zeroValue));
  309. if (value)
  310. {
  311. if (value->compare(zeroValue) < 0)
  312. return LINK(zero);
  313. return LINK(cast);
  314. }
  315. //A bit convoluted, but we only want to evaluate impure expressions (e.g., random()!) once.
  316. //So force them to appear pure (so get commoned up), wrap in an alias, and then create the conditional assignment
  317. if (!cast->isPure())
  318. {
  319. OwnedHqlExpr localAttr = createLocalAttribute();
  320. OwnedHqlExpr pure = createValue(no_pure, cast->getType(), LINK(cast));
  321. cast.setown(createAlias(pure, localAttr));
  322. }
  323. return createValue(no_if, LINK(type), createBoolExpr(no_lt, LINK(cast), LINK(zero)), LINK(zero), LINK(cast));
  324. }
  325. void getOutputLibraryName(SCMStringBuffer & libraryName, IConstWorkUnit * wu)
  326. {
  327. wu->getApplicationValue("LibraryModule", "name", libraryName);
  328. }
  329. IHqlExpression * projectCreateSetDataset(IHqlExpression * expr)
  330. {
  331. IHqlExpression * ds = expr->queryChild(0);
  332. IHqlExpression * select = expr->queryChild(1);
  333. IHqlExpression * record = ds->queryRecord();
  334. //Project down to a single field if necessary. Not needed if selecting the only field in the dataset.
  335. if (queryRealChild(record, 1) || (select->getOperator() != no_select) || (record->queryChild(0) != select->queryChild(1)) || ds->queryNormalizedSelector() != select->queryChild(0))
  336. {
  337. HqlExprArray assigns;
  338. OwnedHqlExpr targetField;
  339. if (select->getOperator() == no_select)
  340. targetField.set(select->queryChild(1));
  341. else
  342. targetField.setown(createFieldFromValue(valueId, select));
  343. IHqlExpression * newRecord = createRecord(targetField);
  344. assigns.append(*createAssign(createSelectExpr(getSelf(newRecord), LINK(targetField)), LINK(select)));
  345. IHqlExpression * newTransform = createValue(no_newtransform, makeTransformType(LINK(newRecord->queryRecordType())), assigns);
  346. HqlExprArray args;
  347. args.append(*LINK(ds));
  348. args.append(*newRecord);
  349. args.append(*newTransform);
  350. OwnedHqlExpr projectedDs = createDataset(no_newusertable, args);
  351. return createValue(no_createset, expr->getType(), LINK(projectedDs), createSelectExpr(LINK(projectedDs), LINK(targetField)));
  352. }
  353. return LINK(expr);
  354. }
  355. bool mustInitializeField(IHqlExpression * field)
  356. {
  357. if (hasLinkCountedModifier(field))
  358. return true;
  359. return false;
  360. }
  361. bool worthGeneratingRowAsSingleActivity(IHqlExpression * expr)
  362. {
  363. for (;;)
  364. {
  365. switch (expr->getOperator())
  366. {
  367. case no_left:
  368. case no_right:
  369. case no_activerow:
  370. case no_createrow:
  371. case no_getresult:
  372. return true;
  373. case no_select:
  374. if (!isNewSelector(expr))
  375. return true;
  376. break;
  377. case no_alias:
  378. case no_projectrow:
  379. break;
  380. case no_if:
  381. return worthGeneratingRowAsSingleActivity(expr->queryChild(1)) && worthGeneratingRowAsSingleActivity(expr->queryChild(2));
  382. default:
  383. //Do not generate no_getgraph result - better as separate activities
  384. return false;
  385. }
  386. expr = expr->queryChild(0);
  387. }
  388. }