fvtransform.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jliball.hpp"
  15. #include "eclrtl.hpp"
  16. #include "fileview.hpp"
  17. #include "fverror.hpp"
  18. #include "fvrelate.ipp"
  19. #include "deftype.hpp"
  20. #include "fvresultset.ipp"
  21. #include "thorplugin.hpp"
  22. #include "eclrtl_imp.hpp"
  23. #include "hqlfold.hpp"
  24. #include "hqlvalid.hpp"
  25. #include "hqlrepository.hpp"
  26. static ViewTransformerRegistry * theTransformerRegistry;
  27. static ITypeInfo * stringType;
  28. static ITypeInfo * utf8Type;
  29. static ITypeInfo * unicodeType;
  30. static _ATOM addAtom;
  31. MODULE_INIT(INIT_PRIORITY_STANDARD)
  32. {
  33. addAtom = createIdentifierAtom("add");
  34. stringType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  35. utf8Type = makeUtf8Type(UNKNOWN_LENGTH, NULL);
  36. unicodeType = makeUnicodeType(UNKNOWN_LENGTH, NULL);
  37. theTransformerRegistry = new ViewTransformerRegistry;
  38. theTransformerRegistry->addTransformer(new ViewFailTransformer);
  39. theTransformerRegistry->addTransformer(new ViewAddTransformer);
  40. return true;
  41. }
  42. MODULE_EXIT()
  43. {
  44. delete theTransformerRegistry;
  45. unicodeType->Release();
  46. utf8Type->Release();
  47. stringType->Release();
  48. }
  49. //---------------------------------------------------------------------------
  50. void CardinalityElement::init(unsigned len, const char * _text)
  51. {
  52. if (len == 0)
  53. {
  54. text.set("1");
  55. min = 1;
  56. max = 1;
  57. return;
  58. }
  59. text.set(_text, len);
  60. const char * dotdot = strstr(text, "..");
  61. if (dotdot)
  62. {
  63. min = rtlStrToUInt4(dotdot-text, text);
  64. if (stricmp(dotdot+2, "M") == 0)
  65. max = Unbounded;
  66. else
  67. max = rtlVStrToUInt4(dotdot+2);
  68. }
  69. else
  70. {
  71. if (stricmp(text, "M") == 0)
  72. {
  73. min = 0;
  74. max = Unbounded;
  75. }
  76. else
  77. {
  78. min = rtlVStrToUInt4(text);
  79. max = min;
  80. }
  81. }
  82. }
  83. void CardinalityMapping::init(const char * text)
  84. {
  85. const char * colon = strchr(text, ':');
  86. if (colon)
  87. {
  88. primary.init(colon-text, text);
  89. secondary.init(strlen(colon+1), colon+1);
  90. }
  91. else
  92. {
  93. //May as well try and make some sense of it
  94. primary.init(0, "");
  95. secondary.init(strlen(text), text);
  96. }
  97. }
  98. void getInvertedCardinality(StringBuffer & out, const char * cardinality)
  99. {
  100. if (cardinality)
  101. {
  102. CardinalityMapping mapping(cardinality);
  103. out.append(mapping.secondary.text).append(":").append(mapping.primary.text);
  104. }
  105. }
  106. //---------------------------------------------------------------------------
  107. ViewFieldTransformer * ViewFieldTransformer::bind(const HqlExprArray & args)
  108. {
  109. return LINK(this);
  110. }
  111. void ViewFieldTransformer::transform(MemoryAttr & utfTarget, const MemoryAttr & utfSrc)
  112. {
  113. //NB: The system utf8 functions typically take a length, whilst MemoryAttr provide a size.
  114. unsigned lenTarget;
  115. char * target;
  116. const char * source = static_cast<const char *>(utfSrc.get());
  117. unsigned lenSource = rtlUtf8Length(utfSrc.length(), source);
  118. transform(lenTarget, target, lenSource, source);
  119. unsigned sizeTarget = rtlUtf8Size(lenTarget, target);
  120. utfTarget.setOwn(lenTarget, target);
  121. }
  122. ViewFailTransformer::ViewFailTransformer() : ViewFieldTransformer(failAtom)
  123. {
  124. }
  125. void ViewFailTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  126. {
  127. throwError(FVERR_FailTransformation);
  128. lenTarget = 0;
  129. target = NULL;
  130. }
  131. ViewAddTransformer::ViewAddTransformer() : ViewFieldTransformer(addAtom)
  132. {
  133. }
  134. ViewAddTransformer::ViewAddTransformer(const HqlExprArray & _args) : ViewFieldTransformer(addAtom)
  135. {
  136. appendArray(args, _args);
  137. }
  138. ViewFieldTransformer * ViewAddTransformer::bind(const HqlExprArray & args)
  139. {
  140. return new ViewAddTransformer(args);
  141. }
  142. void ViewAddTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  143. {
  144. unsigned __int64 value = rtlUtf8ToInt(lenSource, source);
  145. if (args.ordinality())
  146. value += args.item(0).queryValue()->getIntValue();
  147. rtlInt8ToStrX(lenTarget, target, value);
  148. }
  149. //---------------------------------------------------------------------------
  150. void ViewFieldUtf8Transformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  151. {
  152. (*function)(lenTarget, target, lenSource, source);
  153. }
  154. void ViewFieldUnicodeTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  155. {
  156. unsigned lenUnicodeSrc;
  157. unsigned lenUnicodeTarget;
  158. rtlDataAttr unicodeSrc;
  159. rtlDataAttr unicodeTarget;
  160. rtlUtf8ToUnicodeX(lenUnicodeSrc, unicodeSrc.refustr(), lenSource, source);
  161. (*function)(lenUnicodeTarget, unicodeTarget.refustr(), lenUnicodeSrc, unicodeSrc.getustr());
  162. rtlUnicodeToUtf8X(lenTarget, target, lenUnicodeTarget, unicodeTarget.getustr());
  163. }
  164. void ViewFieldStringTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  165. {
  166. unsigned lenStringSrc;
  167. unsigned lenStringTarget;
  168. rtlDataAttr stringSrc;
  169. rtlDataAttr stringTarget;
  170. rtlUtf8ToStrX(lenStringSrc, stringSrc.refstr(), lenSource, source);
  171. (*function)(lenStringTarget, stringTarget.refstr(), lenStringSrc, stringSrc.getstr());
  172. rtlStrToUtf8X(lenTarget, target, lenStringTarget, stringTarget.getstr());
  173. }
  174. //---------------------------------------------------------------------------
  175. ViewFieldTransformer * ViewFieldECLTransformer::bind(const HqlExprArray & args)
  176. {
  177. if (args.ordinality() == 0)
  178. return LINK(this);
  179. return new ViewFieldBoundECLTransformer(this, args);
  180. }
  181. void ViewFieldECLTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source, const HqlExprArray & extraArgs)
  182. {
  183. Owned<ITypeInfo> sourceType = makeUtf8Type(lenSource, 0);
  184. IValue * sourceValue = createUtf8Value(source, LINK(sourceType));
  185. OwnedHqlExpr sourceExpr = createConstant(sourceValue);
  186. HqlExprArray actuals;
  187. actuals.append(*LINK(sourceExpr));
  188. appendArray(actuals, extraArgs);
  189. ThrowingErrorReceiver errors;
  190. OwnedHqlExpr call = createBoundFunction(&errors, function, actuals, NULL, true);
  191. OwnedHqlExpr castValue = ensureExprType(call, utf8Type);
  192. OwnedHqlExpr folded = quickFoldExpression(castValue, NULL, 0);
  193. IValue * foldedValue = folded->queryValue();
  194. assertex(foldedValue);
  195. unsigned len = foldedValue->queryType()->getStringLen();
  196. const char * data = static_cast<const char *>(foldedValue->queryValue());
  197. unsigned size = rtlUtf8Size(len, data);
  198. lenTarget = len;
  199. target = (char *)rtlMalloc(size);
  200. memcpy(target, data, size);
  201. }
  202. void ViewFieldECLTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  203. {
  204. HqlExprArray extraArgs;
  205. transform(lenTarget, target, lenSource, source, extraArgs);
  206. }
  207. void ViewFieldBoundECLTransformer::transform(unsigned & lenTarget, char * & target, unsigned lenSource, const char * source)
  208. {
  209. transformer->transform(lenTarget, target, lenSource, source, args);
  210. }
  211. //---------------------------------------------------------------------------
  212. void ViewTransformerRegistry::addTransformer(ViewFieldTransformer * ownedTransformer)
  213. {
  214. transformers.append(*ownedTransformer);
  215. }
  216. void ViewTransformerRegistry::addFieldUtf8Transformer(const char * name, utf8FieldTransformerFunction func)
  217. {
  218. transformers.append(* new ViewFieldUtf8Transformer(createIdentifierAtom(name), func));
  219. }
  220. void ViewTransformerRegistry::addFieldStringTransformer(const char * name, stringFieldTransformerFunction func)
  221. {
  222. transformers.append(* new ViewFieldStringTransformer(createIdentifierAtom(name), func));
  223. }
  224. void ViewTransformerRegistry::addFieldUnicodeTransformer(const char * name, unicodeFieldTransformerFunction func)
  225. {
  226. transformers.append(* new ViewFieldUnicodeTransformer(createIdentifierAtom(name), func));
  227. }
  228. void ViewTransformerRegistry::addPlugins(const char * name)
  229. {
  230. loadedPlugins.setown(new SafePluginMap(&pluginCtx, true));
  231. loadedPlugins->loadFromList(name);
  232. ThrowingErrorReceiver errors;
  233. dataServer.setown(createSourceFileEclRepository(&errors, name, NULL, NULL, 0));
  234. HqlScopeArray scopes;
  235. HqlLookupContext ctx(NULL, &errors, NULL, dataServer);
  236. dataServer->getRootScopes(scopes, ctx);
  237. ForEachItemIn(i, scopes)
  238. {
  239. IHqlScope * scope = &scopes.item(i);
  240. HqlExprArray symbols;
  241. scope->getSymbols(symbols);
  242. ForEachItemIn(j, symbols)
  243. {
  244. IHqlExpression & cur = symbols.item(j);
  245. if (cur.getOperator() == no_service)
  246. addServiceDefinition(&cur);
  247. }
  248. }
  249. }
  250. static bool matchesSimpleTransformer(IHqlExpression * definition, ITypeInfo * type)
  251. {
  252. if (definition->queryBody()->queryType() != type)
  253. return false;
  254. if (definition->numChildren() != 2)
  255. return false;
  256. if (definition->queryChild(1)->queryType() != type)
  257. return false;
  258. return true;
  259. }
  260. void * ViewTransformerRegistry::resolveExternal(IHqlExpression * funcdef)
  261. {
  262. IHqlExpression *body = funcdef->queryChild(0);
  263. StringBuffer entry;
  264. StringBuffer lib;
  265. getProperty(body, entrypointAtom, entry);
  266. getProperty(body, libraryAtom, lib);
  267. if (!lib.length())
  268. getProperty(body, pluginAtom, lib);
  269. ensureFileExtension(lib, SharedObjectExtension);
  270. Owned<ILoadedDllEntry> match = loadedPlugins->getPluginDll(lib.toCharArray(), NULL, false); // MORE - shouldn't it check the version????
  271. if (!match)
  272. return NULL;
  273. return GetSharedProcedure(match->getInstance(), entry.toCharArray());
  274. }
  275. ViewFieldTransformer * ViewTransformerRegistry::createTransformer(IHqlExpression * funcdef)
  276. {
  277. IHqlExpression *body = funcdef->queryChild(0);
  278. if(!body)
  279. return NULL;
  280. StringBuffer entry;
  281. StringBuffer lib;
  282. getProperty(body, entrypointAtom, entry);
  283. getProperty(body, libraryAtom, lib);
  284. if (!lib.length())
  285. getProperty(body, pluginAtom, lib);
  286. if ((entry.length() == 0) || (lib.length() == 0))
  287. return NULL;
  288. if(!body->hasProperty(pureAtom) && !body->hasProperty(templateAtom))
  289. return NULL;
  290. if(!body->hasProperty(cAtom))
  291. return NULL;
  292. if(body->hasProperty(gctxmethodAtom) || body->hasProperty(ctxmethodAtom) || body->hasProperty(omethodAtom))
  293. return NULL;
  294. if(body->hasProperty(contextAtom) || body->hasProperty(globalContextAtom))
  295. return NULL;
  296. //Special case string->string mapping (e.g., uppercase)
  297. if (matchesSimpleTransformer(funcdef, stringType))
  298. {
  299. stringFieldTransformerFunction resolved = (stringFieldTransformerFunction)resolveExternal(funcdef);
  300. if (resolved)
  301. return new ViewFieldStringTransformer(funcdef->queryName(), resolved);
  302. }
  303. //Special case string->string mapping (e.g., uppercase)
  304. if (matchesSimpleTransformer(funcdef, unicodeType))
  305. {
  306. unicodeFieldTransformerFunction resolved = (unicodeFieldTransformerFunction)resolveExternal(funcdef);
  307. if (resolved)
  308. return new ViewFieldUnicodeTransformer(funcdef->queryName(), resolved);
  309. }
  310. //MORE: special case string->string etc.
  311. return new ViewFieldECLTransformer(funcdef);
  312. }
  313. void ViewTransformerRegistry::addServiceDefinition(IHqlExpression * service)
  314. {
  315. Owned<ViewServiceEntry> entry = new ViewServiceEntry;
  316. entry->name.set(service->queryName()->str());
  317. HqlExprArray symbols;
  318. service->queryScope()->getSymbols(symbols);
  319. ForEachItemIn(i, symbols)
  320. {
  321. IHqlExpression & cur = symbols.item(i);
  322. if (cur.getOperator() == no_funcdef && cur.queryChild(0)->getOperator() == no_external)
  323. {
  324. ViewFieldTransformer * transformer = createTransformer(&cur);
  325. if (transformer)
  326. entry->transformers.append(*transformer);
  327. }
  328. }
  329. plugins.append(*entry.getClear());
  330. }
  331. ViewFieldTransformer * find(const ViewFieldTransformerArray & transformers, const char * name, const HqlExprArray & args)
  332. {
  333. if (!name)
  334. return NULL;
  335. _ATOM search = createIdentifierAtom(name);
  336. ForEachItemIn(i, transformers)
  337. {
  338. ViewFieldTransformer & cur = transformers.item(i);
  339. if (cur.matches(search))
  340. return cur.bind(args);
  341. }
  342. return NULL;
  343. }
  344. ViewFieldTransformer * ViewTransformerRegistry::resolve(const char * name, const HqlExprArray & args)
  345. {
  346. return find(transformers, name, args);
  347. }
  348. ViewFieldTransformer * ViewTransformerRegistry::resolve(const char * servicename, const char * functionName, const HqlExprArray & args)
  349. {
  350. if (!servicename)
  351. return NULL;
  352. ForEachItemIn(i, plugins)
  353. {
  354. ViewServiceEntry & cur = plugins.item(i);
  355. if (stricmp(servicename, cur.name) == 0)
  356. return find(cur.transformers, functionName, args);
  357. }
  358. return NULL;
  359. }
  360. IViewTransformerRegistry & queryTransformerRegistry()
  361. {
  362. return *theTransformerRegistry;
  363. }
  364. //---------------------------------------------------------------------------
  365. bool containsFail(const ViewFieldTransformerArray & transforms)
  366. {
  367. ForEachItemIn(i, transforms)
  368. {
  369. if (transforms.item(i).matches(failAtom))
  370. return true;
  371. }
  372. return false;
  373. }
  374. void translateValue(MemoryAttr & result, const MemoryAttr & filterValue, const ViewFieldTransformerArray & transforms)
  375. {
  376. unsigned numTransforms = transforms.ordinality();
  377. if (numTransforms)
  378. {
  379. MemoryAttr tempValue[2];
  380. unsigned whichTarget = 0;
  381. const MemoryAttr * source = &filterValue;
  382. for (unsigned i=0; i < numTransforms-1; i++)
  383. {
  384. MemoryAttr * target = &tempValue[whichTarget];
  385. transforms.item(i).transform(*target, *source);
  386. source = target;
  387. whichTarget = 1-whichTarget;
  388. }
  389. transforms.item(numTransforms-1).transform(result, *source);
  390. }
  391. else
  392. result.set(filterValue.length(), filterValue.get());
  393. }
  394. ViewJoinColumn::ViewJoinColumn(unsigned _whichColumn, const ViewFieldTransformerArray & _getTransforms, const ViewFieldTransformerArray & _setTransforms)
  395. {
  396. whichColumn = _whichColumn;
  397. appendArray(getTransforms, _getTransforms);
  398. appendArray(setTransforms, _setTransforms);
  399. getContainsFail = containsFail(getTransforms);
  400. setContainsFail = containsFail(setTransforms);
  401. }
  402. void ViewJoinColumn::addFilter(IFilteredResultSet * resultSet, const MemoryAttr & value)
  403. {
  404. const MemoryAttr * source = &value;
  405. MemoryAttr tempValue;
  406. if (setTransforms.ordinality())
  407. {
  408. translateValue(tempValue, value, setTransforms);
  409. source = &tempValue;
  410. }
  411. resultSet->addFilter(whichColumn, source->length(), (const char *)source->get());
  412. }
  413. void ViewJoinColumn::clearFilter(IFilteredResultSet * resultSet)
  414. {
  415. resultSet->clearFilter(whichColumn);
  416. }
  417. void ViewJoinColumn::getValue(MemoryAttr & value, IResultSetCursor * cursor)
  418. {
  419. if (getTransforms.ordinality())
  420. {
  421. MemoryAttr rowValue;
  422. MemoryAttr2IStringVal adaptor(rowValue);
  423. cursor->getDisplayText(adaptor, whichColumn);
  424. translateValue(value, rowValue, getTransforms);
  425. }
  426. else
  427. {
  428. MemoryAttr2IStringVal adaptor(value);
  429. cursor->getDisplayText(adaptor, whichColumn);
  430. }
  431. }
  432. //---------------------------------------------------------------------------
  433. struct TextReference
  434. {
  435. TextReference() { len =0; text = NULL; }
  436. TextReference(size32_t _len, const char * _text) : len(_len), text(_text) {}
  437. inline bool eq(const char * search) const { return (len == strlen(search)) && (memicmp(text, search, len) == 0); }
  438. inline void get(StringAttr & target) const { target.set(text, len); }
  439. void set(size32_t _len, const char * _text) { len = _len; text = _text; }
  440. IHqlExpression * createIntConstant();
  441. IHqlExpression * createStringConstant();
  442. size32_t len;
  443. const char * text;
  444. };
  445. IHqlExpression * TextReference::createIntConstant()
  446. {
  447. return createConstant(rtlStrToInt8(len, text));
  448. }
  449. IHqlExpression * TextReference::createStringConstant()
  450. {
  451. return createConstant(createUnicodeValue(text+1, len-2, "", true, true));
  452. }
  453. class MappingParser
  454. {
  455. enum { TokEof=256, TokId, TokInt, TokString };
  456. public:
  457. MappingParser(const IResultSetMetaData & _fieldMeta, bool _datasetSelectorAllowed) : fieldMeta(_fieldMeta), datasetSelectorAllowed(_datasetSelectorAllowed) {}
  458. void parseColumnMappingList(FieldTransformInfoArray & results, unsigned len, const char * text);
  459. protected:
  460. unsigned lexToken();
  461. void assertToken(int expected);
  462. void getTokenText(StringAttr & target) { curToken.get(target); }
  463. void parseAttribute(FieldTransformInfo & output);
  464. void parseColumn(FieldTransformInfo & output);
  465. void parseColumnMapping(FieldTransformInfo & output);
  466. void parseConstantList(HqlExprArray & args);
  467. void parseTransformList(ViewFieldTransformerArray & transforms);
  468. protected:
  469. const IResultSetMetaData & fieldMeta;
  470. bool datasetSelectorAllowed;
  471. unsigned tokenType;
  472. TextReference curToken;
  473. unsigned offset;
  474. unsigned lenInput;
  475. const char * input;
  476. };
  477. inline bool isLeadingIdentChar(byte next)
  478. {
  479. return isalpha(next) || (next == '_') || (next == '$');
  480. }
  481. inline bool isTrailingIdentChar(byte next)
  482. {
  483. return isalnum(next) || (next == '_') || (next == '$');
  484. }
  485. //MORE: This should really use the hqllexer - especially if it gets any more complex!
  486. unsigned MappingParser::lexToken()
  487. {
  488. const byte * buffer = (const byte *)input;
  489. unsigned cur = offset;
  490. while ((cur < lenInput) && isspace(buffer[cur]))
  491. cur++;
  492. if (cur < lenInput)
  493. {
  494. byte next = buffer[cur];
  495. if (isLeadingIdentChar(next))
  496. {
  497. cur++;
  498. while ((cur < lenInput) && (isTrailingIdentChar(buffer[cur])))
  499. cur++;
  500. tokenType = TokId;
  501. }
  502. else if (isdigit(next) ||
  503. ((next == '-') && (cur+1 < lenInput) && isdigit(buffer[cur+1])))
  504. {
  505. cur++;
  506. while ((cur < lenInput) && (isdigit(buffer[cur])))
  507. cur++;
  508. tokenType = TokInt;
  509. }
  510. else if (next == '\'')
  511. {
  512. cur++;
  513. while (cur < lenInput)
  514. {
  515. byte next = buffer[cur];
  516. if (next == '\'')
  517. break;
  518. else if (next == '\\')
  519. {
  520. if (cur+1 < lenInput)
  521. cur++;
  522. }
  523. cur++;
  524. }
  525. if (cur == lenInput)
  526. throwError2(FVERR_BadStringTermination, cur-offset, input+offset);
  527. cur++;
  528. tokenType = TokString;
  529. }
  530. else
  531. {
  532. tokenType = next;
  533. cur++;
  534. }
  535. }
  536. else
  537. {
  538. tokenType = TokEof;
  539. }
  540. curToken.set(cur-offset, input+offset);
  541. offset = cur;
  542. return tokenType;
  543. }
  544. void MappingParser::assertToken(int expected)
  545. {
  546. if (tokenType != expected)
  547. {
  548. StringBuffer id;
  549. switch (expected)
  550. {
  551. case TokId:
  552. id.append("identifier");
  553. break;
  554. default:
  555. id.append((char)expected);
  556. break;
  557. }
  558. unsigned len = lenInput-offset;
  559. if (len>10) len = 10;
  560. throwError3(FVERR_ExpectedX, id.str(), len, input+offset);
  561. }
  562. }
  563. void MappingParser::parseColumn(FieldTransformInfo & output)
  564. {
  565. output.datasetColumn = NotFound;
  566. output.column = NotFound;
  567. unsigned firstFieldIndex = 0;
  568. const IResultSetMetaData * curMeta = &fieldMeta;
  569. loop
  570. {
  571. StringAttr fieldName;
  572. assertToken(TokId);
  573. getTokenText(fieldName);
  574. lexToken();
  575. //Cheat and cast the meta so the field lookup can be done more efficiently
  576. const CResultSetMetaData & castFieldMeta = static_cast<const CResultSetMetaData &>(*curMeta);
  577. unsigned matchColumn = castFieldMeta.queryColumnIndex(firstFieldIndex, fieldName);
  578. if (matchColumn == NotFound)
  579. throwError1(FVERR_UnrecognisedFieldX, fieldName.get());
  580. DisplayType kind = fieldMeta.getColumnDisplayType(matchColumn);
  581. switch (kind)
  582. {
  583. case TypeBoolean:
  584. case TypeInteger:
  585. case TypeUnsignedInteger:
  586. case TypeReal:
  587. case TypeString:
  588. case TypeData:
  589. case TypeUnicode:
  590. case TypeUnknown:
  591. case TypeSet:
  592. output.column = matchColumn;
  593. break;
  594. case TypeBeginRecord:
  595. //Restrict the search fields to the contents of the record.
  596. firstFieldIndex = matchColumn+1;
  597. break;
  598. case TypeDataset:
  599. {
  600. if (!datasetSelectorAllowed)
  601. throwError1(FVERR_CannotSelectFromDatasetX, fieldName.get());
  602. if (output.datasetColumn != NotFound)
  603. throwError1(FVERR_CannotSelectManyFromDatasetX, fieldName.get());
  604. firstFieldIndex = 0;
  605. curMeta = curMeta->getChildMeta(matchColumn);
  606. output.datasetColumn = matchColumn;
  607. break;
  608. }
  609. default:
  610. throwUnexpected();
  611. }
  612. if (output.column != NotFound)
  613. return;
  614. assertToken('.');
  615. lexToken();
  616. }
  617. }
  618. void MappingParser::parseConstantList(HqlExprArray & args)
  619. {
  620. loop
  621. {
  622. switch (tokenType)
  623. {
  624. case TokInt:
  625. args.append(*curToken.createIntConstant());
  626. break;
  627. case TokString:
  628. args.append(*curToken.createStringConstant());
  629. break;
  630. default:
  631. unsigned len = lenInput - offset > 10 ? 10 : lenInput - offset;
  632. throwError3(FVERR_ExpectedX, "int or string constant", len, input+offset);
  633. }
  634. lexToken();
  635. if (tokenType != ',')
  636. return;
  637. lexToken();
  638. }
  639. }
  640. void MappingParser::parseTransformList(ViewFieldTransformerArray & transforms)
  641. {
  642. loop
  643. {
  644. assertToken(TokId);
  645. StringAttr mappingName, childName, grandName;
  646. curToken.get(mappingName);
  647. lexToken();
  648. if (tokenType == '.')
  649. {
  650. lexToken();
  651. assertToken(TokId);
  652. curToken.get(childName);
  653. lexToken();
  654. }
  655. if (tokenType == '.')
  656. {
  657. lexToken();
  658. assertToken(TokId);
  659. curToken.get(grandName);
  660. lexToken();
  661. }
  662. HqlExprArray args;
  663. if (tokenType == '(')
  664. {
  665. lexToken();
  666. if (tokenType != ')')
  667. parseConstantList(args);
  668. assertToken(')');
  669. lexToken();
  670. }
  671. ViewFieldTransformer * transform;
  672. if (childName)
  673. {
  674. transform = theTransformerRegistry->resolve(mappingName, childName, args);
  675. if (!transform)
  676. {
  677. //Maybe they specified the module name - should provide a 3 valued lookup
  678. transform = theTransformerRegistry->resolve(childName, grandName, args);
  679. }
  680. if (!transform)
  681. throwError2(FVERR_UnrecognisedMappingFunctionXY, mappingName.get(), childName.get());
  682. }
  683. else
  684. {
  685. transform = theTransformerRegistry->resolve(mappingName, args);
  686. if (!transform)
  687. throwError1(FVERR_UnrecognisedMappingFunctionX, mappingName.get());
  688. }
  689. transforms.append(*transform);
  690. if (tokenType != ',')
  691. break;
  692. lexToken();
  693. }
  694. }
  695. void MappingParser::parseAttribute(FieldTransformInfo & output)
  696. {
  697. assertToken(TokId);
  698. if (curToken.eq("get"))
  699. {
  700. lexToken();
  701. assertToken('(');
  702. lexToken();
  703. parseTransformList(output.getTransforms);
  704. assertToken(')');
  705. lexToken();
  706. }
  707. else if (curToken.eq("set"))
  708. {
  709. lexToken();
  710. assertToken('(');
  711. lexToken();
  712. parseTransformList(output.setTransforms);
  713. assertToken(')');
  714. lexToken();
  715. }
  716. else if (curToken.eq("displayname"))
  717. {
  718. lexToken();
  719. assertToken('(');
  720. lexToken();
  721. assertToken(TokId); // could allow a string I guess
  722. curToken.get(output.naturalName);
  723. lexToken();
  724. assertToken(')');
  725. lexToken();
  726. }
  727. else
  728. throwError1(FVERR_ExpectedX, "Definition name");
  729. }
  730. void MappingParser::parseColumnMapping(FieldTransformInfo & output)
  731. {
  732. parseColumn(output);
  733. int endToken = '}';
  734. //be flexible and allow () or {}?
  735. if (tokenType == '(')
  736. endToken = ')';
  737. else if (tokenType != '{')
  738. return;
  739. lexToken();
  740. if (tokenType != endToken)
  741. {
  742. loop
  743. {
  744. parseAttribute(output);
  745. if (tokenType != ',')
  746. break;
  747. lexToken();
  748. }
  749. }
  750. assertToken(endToken);
  751. lexToken();
  752. }
  753. void MappingParser::parseColumnMappingList(FieldTransformInfoArray & results, unsigned len, const char * text)
  754. {
  755. lenInput = len;
  756. input = text;
  757. offset = 0;
  758. lexToken();
  759. if (tokenType == TokEof)
  760. return;
  761. loop
  762. {
  763. FieldTransformInfo * next = new FieldTransformInfo;
  764. results.append(*next);
  765. parseColumnMapping(*next);
  766. if (tokenType == TokEof)
  767. break;
  768. assertToken(',');
  769. lexToken();
  770. }
  771. }
  772. void parseColumnMappingList(FieldTransformInfoArray & results,
  773. const IResultSetMetaData & fieldMeta,
  774. bool isDatasetAllowed, // if non null dataset.x is allowed, and column returned via pointer
  775. const char * text)
  776. {
  777. MappingParser parser(fieldMeta, isDatasetAllowed);
  778. parser.parseColumnMappingList(results, strlen(text), text);
  779. }
  780. void parseFileColumnMapping(FieldTransformInfoArray & results, const char * text, const IResultSetMetaData & fieldMeta)
  781. {
  782. MappingParser parser(fieldMeta, false);
  783. parser.parseColumnMappingList(results, strlen(text), text);
  784. }
  785. static void test()
  786. {
  787. HqlExprArray args;
  788. MemoryAttr source;
  789. source.set(26,"Gavin H\303\243lliday !!\316\261\316\221\307\272!!");
  790. {
  791. Owned<ViewFieldTransformer> transform = theTransformerRegistry->resolve("stringlib","StringToUpperCase",args);
  792. MemoryAttr target;
  793. transform->transform(target, source);
  794. }
  795. {
  796. Owned<ViewFieldTransformer> transform = theTransformerRegistry->resolve("unicodelib","UnicodeToUpperCase",args);
  797. MemoryAttr target;
  798. transform->transform(target, source);
  799. }
  800. source.get();
  801. }