Rembed.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  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. #ifdef RCPP_HEADER_ONLY
  15. // NOTE - these symbols need to be hidden from being exported from the Rembed .so file as RInside tries to dynamically
  16. // load them from Rcpp.so
  17. // If future versions of Rcpp add any (in Rcpp/routines.h) they may need to be added here too.
  18. #define type2name HIDE_RCPP_type2name
  19. #define enterRNGScope HIDE_RCPP_enterRNGScope
  20. #define exitRNGScope HIDE_RCPP_exitRNGScope
  21. #define get_string_buffer HIDE_RCPP_get_string_buffer
  22. #define get_Rcpp_namespace HIDE_RCPP_get_Rcpp_namespace
  23. #define mktime00 HIDE_RCPP_mktime00_
  24. #define gmtime_ HIDE_RCPP_gmtime_
  25. #define rcpp_get_stack_trace HIDE_RCPP_rcpp_get_stack_trace
  26. #define rcpp_set_stack_trace HIDE_RCPP_rcpp_set_stack_trace
  27. #define demangle HIDE_RCPP_demangle
  28. #define short_file_name HIDE_RCPP_short_file_name
  29. #define stack_trace HIDE_RCPP_stack_trace
  30. #define get_string_elt HIDE_RCPP_get_string_elt
  31. #define char_get_string_elt HIDE_RCPP_char_get_string_elt
  32. #define set_string_elt HIDE_RCPP_set_string_elt
  33. #define char_set_string_elt HIDE_RCPP_char_set_string_elt
  34. #define get_string_ptr HIDE_RCPP_get_string_ptr
  35. #define get_vector_elt HIDE_RCPP_get_vector_elt
  36. #define set_vector_elt HIDE_RCPP_set_vector_elt
  37. #define get_vector_ptr HIDE_RCPP_get_vector_ptr
  38. #define char_nocheck HIDE_RCPP_char_nocheck
  39. #define dataptr HIDE_RCPP_dataptr
  40. #define getCurrentScope HIDE_RCPP_getCurrentScope
  41. #define setCurrentScope HIDE_RCPP_setCurrentScope
  42. #define get_cache HIDE_RCPP_get_cache
  43. #define reset_current_error HIDE_RCPP_reset_current_error
  44. #define error_occured HIDE_RCPP_error_occured
  45. #define rcpp_get_current_error HIDE_RCPP_rcpp_get_current_error
  46. #endif
  47. #include "RInside.h"
  48. #include "jexcept.hpp"
  49. #include "jthread.hpp"
  50. #include "hqlplugins.hpp"
  51. #include "deftype.hpp"
  52. #include "eclrtl.hpp"
  53. #include "eclrtl_imp.hpp"
  54. #include "rtlds_imp.hpp"
  55. #include "rtlfield_imp.hpp"
  56. #include "nbcd.hpp"
  57. #ifdef _WIN32
  58. #define EXPORT __declspec(dllexport)
  59. #else
  60. #define EXPORT
  61. #endif
  62. static const char * compatibleVersions[] =
  63. { "R Embed Helper 1.0.0", NULL };
  64. static const char *version = "R Embed Helper 1.0.0";
  65. extern "C" EXPORT bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
  66. {
  67. if (pb->size == sizeof(ECLPluginDefinitionBlockEx))
  68. {
  69. ECLPluginDefinitionBlockEx * pbx = (ECLPluginDefinitionBlockEx *) pb;
  70. pbx->compatibleVersions = compatibleVersions;
  71. }
  72. else if (pb->size != sizeof(ECLPluginDefinitionBlock))
  73. return false;
  74. pb->magicVersion = PLUGIN_VERSION;
  75. pb->version = version;
  76. pb->moduleName = "+R+"; // Hack - we don't want to export any ECL, but if we don't export something,
  77. pb->ECL = ""; // Hack - the dll is unloaded at startup when compiling, and the R runtime closes stdin when unloaded
  78. pb->flags = PLUGIN_MULTIPLE_VERSIONS;
  79. pb->description = "R Embed Helper";
  80. return true;
  81. }
  82. #ifdef _WIN32
  83. EXTERN_C IMAGE_DOS_HEADER __ImageBase;
  84. #endif
  85. #define UNSUPPORTED(feature) throw MakeStringException(MSGAUD_user, 0, "Rembed: UNSUPPORTED feature: %s", feature)
  86. #define FAIL(msg) throw MakeStringException(MSGAUD_user, 0, "Rembed: Rcpp error: %s", msg)
  87. namespace Rembed
  88. {
  89. class OwnedRoxieRowSet : public ConstPointerArray
  90. {
  91. public:
  92. ~OwnedRoxieRowSet()
  93. {
  94. ForEachItemIn(idx, *this)
  95. rtlReleaseRow(item(idx));
  96. }
  97. };
  98. // Use a global object to ensure that the R instance is initialized only once
  99. // Because of R's dodgy stack checks, we also have to do so on main thread
  100. static class RGlobalState
  101. {
  102. public:
  103. RGlobalState()
  104. {
  105. const char *args[] = {"R", "--slave" };
  106. R = new RInside(2, args, true, false, true); // Setting interactive mode=true prevents R syntax errors from terminating the process
  107. // The R code for checking stack limits assumes that all calls are on the same thread
  108. // as the original context was created on - this will not always be true in ECL (and hardly
  109. // ever true in Roxie
  110. // Setting the stack limit to -1 disables this check
  111. R_CStackLimit = -1;
  112. // Make sure we are never unloaded (as R does not support it)
  113. // we do this by doing a dynamic load of the Rembed library
  114. #ifdef _WIN32
  115. char path[_MAX_PATH];
  116. ::GetModuleFileName((HINSTANCE)&__ImageBase, path, _MAX_PATH);
  117. if (strstr(path, "Rembed"))
  118. {
  119. HINSTANCE h = LoadSharedObject(path, false, false);
  120. DBGLOG("LoadSharedObject returned %p", h);
  121. }
  122. #else
  123. FILE *diskfp = fopen("/proc/self/maps", "r");
  124. if (diskfp)
  125. {
  126. char ln[_MAX_PATH];
  127. while (fgets(ln, sizeof(ln), diskfp))
  128. {
  129. if (strstr(ln, "libRembed"))
  130. {
  131. const char *fullName = strchr(ln, '/');
  132. if (fullName)
  133. {
  134. char *tail = (char *) strstr(fullName, SharedObjectExtension);
  135. if (tail)
  136. {
  137. tail[strlen(SharedObjectExtension)] = 0;
  138. HINSTANCE h = LoadSharedObject(fullName, false, false);
  139. break;
  140. }
  141. }
  142. }
  143. }
  144. fclose(diskfp);
  145. }
  146. #endif
  147. }
  148. ~RGlobalState()
  149. {
  150. delete R;
  151. }
  152. RInside *R;
  153. }* globalState = NULL;
  154. static CriticalSection RCrit; // R is single threaded - need to own this before making any call to R
  155. static RGlobalState *queryGlobalState()
  156. {
  157. CriticalBlock b(RCrit);
  158. if (!globalState)
  159. globalState = new RGlobalState;
  160. return globalState;
  161. }
  162. extern void unload()
  163. {
  164. CriticalBlock b(RCrit);
  165. if (globalState)
  166. delete globalState;
  167. globalState = NULL;
  168. }
  169. MODULE_INIT(INIT_PRIORITY_STANDARD)
  170. {
  171. queryGlobalState(); // make sure gets loaded by main thread
  172. return true;
  173. }
  174. MODULE_EXIT()
  175. {
  176. // Don't unload, because R seems to have problems with being reloaded, i.e. crashes on next use
  177. // unload();
  178. }
  179. // A RDataFrameHeaderBuilder object is used to construct the header for an R dataFrame from an ECL row
  180. class RDataFrameHeaderBuilder : public CInterfaceOf<IFieldProcessor>
  181. {
  182. public:
  183. RDataFrameHeaderBuilder()
  184. {
  185. }
  186. virtual void processString(unsigned len, const char *value, const RtlFieldInfo * field)
  187. {
  188. addField(field);
  189. }
  190. virtual void processBool(bool value, const RtlFieldInfo * field)
  191. {
  192. addField(field);
  193. }
  194. virtual void processData(unsigned len, const void *value, const RtlFieldInfo * field)
  195. {
  196. addField(field);
  197. }
  198. virtual void processInt(__int64 value, const RtlFieldInfo * field)
  199. {
  200. addField(field);
  201. }
  202. virtual void processUInt(unsigned __int64 value, const RtlFieldInfo * field)
  203. {
  204. addField(field);
  205. }
  206. virtual void processReal(double value, const RtlFieldInfo * field)
  207. {
  208. addField(field);
  209. }
  210. virtual void processDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  211. {
  212. addField(field);
  213. }
  214. virtual void processUDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  215. {
  216. addField(field);
  217. }
  218. virtual void processUnicode(unsigned len, const UChar *value, const RtlFieldInfo * field)
  219. {
  220. UNSUPPORTED("Unicode/UTF8 fields");
  221. }
  222. virtual void processQString(unsigned len, const char *value, const RtlFieldInfo * field)
  223. {
  224. addField(field);
  225. }
  226. virtual void processSetAll(const RtlFieldInfo * field)
  227. {
  228. UNSUPPORTED("SET fields");
  229. }
  230. virtual void processUtf8(unsigned len, const char *value, const RtlFieldInfo * field)
  231. {
  232. UNSUPPORTED("Unicode/UTF8 fields");
  233. }
  234. virtual bool processBeginSet(const RtlFieldInfo * field, unsigned elements, bool isAll, const byte *data)
  235. {
  236. UNSUPPORTED("SET fields");
  237. }
  238. virtual bool processBeginDataset(const RtlFieldInfo * field, unsigned rows)
  239. {
  240. UNSUPPORTED("Nested datasets");
  241. }
  242. virtual bool processBeginRow(const RtlFieldInfo * field)
  243. {
  244. return true;
  245. }
  246. virtual void processEndSet(const RtlFieldInfo * field)
  247. {
  248. UNSUPPORTED("SET fields");
  249. }
  250. virtual void processEndDataset(const RtlFieldInfo * field)
  251. {
  252. UNSUPPORTED("Nested datasets");
  253. }
  254. virtual void processEndRow(const RtlFieldInfo * field)
  255. {
  256. }
  257. Rcpp::CharacterVector namevec;
  258. protected:
  259. void addField(const RtlFieldInfo * field)
  260. {
  261. namevec.push_back(field->name->queryStr());
  262. }
  263. };
  264. // A RDataFrameHeaderBuilder object is used to construct the header for an R dataFrame from an ECL row
  265. class RDataFrameAppender : public CInterfaceOf<IFieldProcessor>
  266. {
  267. public:
  268. RDataFrameAppender(Rcpp::List &_list) : list(_list)
  269. {
  270. colIdx = 0;
  271. rowIdx = 0;
  272. }
  273. inline void setRowIdx(unsigned _idx)
  274. {
  275. colIdx = 0;
  276. rowIdx = _idx;
  277. }
  278. virtual void processString(unsigned len, const char *value, const RtlFieldInfo * field)
  279. {
  280. std::string s(value, len);
  281. Rcpp::List column = list[colIdx];
  282. column[rowIdx] = s;
  283. colIdx++;
  284. }
  285. virtual void processBool(bool value, const RtlFieldInfo * field)
  286. {
  287. Rcpp::List column = list[colIdx];
  288. column[rowIdx] = value;
  289. colIdx++;
  290. }
  291. virtual void processData(unsigned len, const void *value, const RtlFieldInfo * field)
  292. {
  293. std::vector<byte> vval;
  294. const byte *cval = (const byte *) value;
  295. vval.assign(cval, cval+len);
  296. Rcpp::List column = list[colIdx];
  297. column[rowIdx] = vval;
  298. colIdx++;
  299. }
  300. virtual void processInt(__int64 value, const RtlFieldInfo * field)
  301. {
  302. Rcpp::List column = list[colIdx];
  303. column[rowIdx] = (long int) value; // Rcpp does not support int64
  304. colIdx++;
  305. }
  306. virtual void processUInt(unsigned __int64 value, const RtlFieldInfo * field)
  307. {
  308. Rcpp::List column = list[colIdx];
  309. column[rowIdx] = (unsigned long int) value; // Rcpp does not support int64
  310. colIdx++;
  311. }
  312. virtual void processReal(double value, const RtlFieldInfo * field)
  313. {
  314. Rcpp::List column = list[colIdx];
  315. column[rowIdx] = value;
  316. colIdx++;
  317. }
  318. virtual void processDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  319. {
  320. Decimal val;
  321. val.setDecimal(digits, precision, value);
  322. Rcpp::List column = list[colIdx];
  323. column[rowIdx] = val.getReal();
  324. colIdx++;
  325. }
  326. virtual void processUDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  327. {
  328. Decimal val;
  329. val.setUDecimal(digits, precision, value);
  330. Rcpp::List column = list[colIdx];
  331. column[rowIdx] = val.getReal();
  332. colIdx++;
  333. }
  334. virtual void processUnicode(unsigned len, const UChar *value, const RtlFieldInfo * field)
  335. {
  336. UNSUPPORTED("Unicode/UTF8 fields");
  337. }
  338. virtual void processQString(unsigned len, const char *value, const RtlFieldInfo * field)
  339. {
  340. size32_t charCount;
  341. rtlDataAttr text;
  342. rtlQStrToStrX(charCount, text.refstr(), len, value);
  343. processString(charCount, text.getstr(), field);
  344. }
  345. virtual void processSetAll(const RtlFieldInfo * field)
  346. {
  347. UNSUPPORTED("SET fields");
  348. }
  349. virtual void processUtf8(unsigned len, const char *value, const RtlFieldInfo * field)
  350. {
  351. UNSUPPORTED("Unicode/UTF8 fields");
  352. }
  353. virtual bool processBeginSet(const RtlFieldInfo * field, unsigned elements, bool isAll, const byte *data)
  354. {
  355. UNSUPPORTED("SET fields");
  356. }
  357. virtual bool processBeginDataset(const RtlFieldInfo * field, unsigned rows)
  358. {
  359. UNSUPPORTED("Nested datasets");
  360. }
  361. virtual bool processBeginRow(const RtlFieldInfo * field)
  362. {
  363. return true;
  364. }
  365. virtual void processEndSet(const RtlFieldInfo * field)
  366. {
  367. UNSUPPORTED("SET fields");
  368. }
  369. virtual void processEndDataset(const RtlFieldInfo * field)
  370. {
  371. UNSUPPORTED("Nested datasets");
  372. }
  373. virtual void processEndRow(const RtlFieldInfo * field)
  374. {
  375. }
  376. protected:
  377. unsigned rowIdx;
  378. unsigned colIdx;
  379. Rcpp::List &list;
  380. };
  381. // A RRowBuilder object is used to construct an ECL row from a R dataframe and row index
  382. class RRowBuilder : public CInterfaceOf<IFieldSource>
  383. {
  384. public:
  385. RRowBuilder(Rcpp::DataFrame &_frame)
  386. : frame(_frame)
  387. {
  388. rowIdx = 0;
  389. colIdx = 0;
  390. }
  391. inline void setRowIdx(unsigned _rowIdx)
  392. {
  393. rowIdx = _rowIdx;
  394. colIdx = 0;
  395. }
  396. virtual bool getBooleanResult(const RtlFieldInfo *field)
  397. {
  398. nextField(field);
  399. return ::Rcpp::as<bool>(elem);
  400. }
  401. virtual void getDataResult(const RtlFieldInfo *field, size32_t &__len, void * &__result)
  402. {
  403. nextField(field);
  404. std::vector<byte> vval = ::Rcpp::as<std::vector<byte> >(elem);
  405. rtlStrToDataX(__len, __result, vval.size(), vval.data());
  406. }
  407. virtual double getRealResult(const RtlFieldInfo *field)
  408. {
  409. nextField(field);
  410. return ::Rcpp::as<double>(elem);
  411. }
  412. virtual __int64 getSignedResult(const RtlFieldInfo *field)
  413. {
  414. nextField(field);
  415. return ::Rcpp::as<long int>(elem); // Should really be long long, but RInside does not support that
  416. }
  417. virtual unsigned __int64 getUnsignedResult(const RtlFieldInfo *field)
  418. {
  419. nextField(field);
  420. return ::Rcpp::as<unsigned long int>(elem); // Should really be long long, but RInside does not support that
  421. }
  422. virtual void getStringResult(const RtlFieldInfo *field, size32_t &__len, char * &__result)
  423. {
  424. nextField(field);
  425. std::string str = ::Rcpp::as<std::string>(elem);
  426. rtlStrToStrX(__len, __result, str.length(), str.data());
  427. }
  428. virtual void getUTF8Result(const RtlFieldInfo *field, size32_t &chars, char * &result)
  429. {
  430. UNSUPPORTED("Unicode/UTF8 fields");
  431. }
  432. virtual void getUnicodeResult(const RtlFieldInfo *field, size32_t &chars, UChar * &result)
  433. {
  434. UNSUPPORTED("Unicode/UTF8 fields");
  435. }
  436. virtual void getDecimalResult(const RtlFieldInfo *field, Decimal &value)
  437. {
  438. nextField(field);
  439. double ret = ::Rcpp::as<double>(elem);
  440. value.setReal(ret);
  441. }
  442. virtual void processBeginSet(const RtlFieldInfo * field, bool &isAll)
  443. {
  444. UNSUPPORTED("SET fields");
  445. }
  446. virtual bool processNextSet(const RtlFieldInfo * field)
  447. {
  448. UNSUPPORTED("SET fields");
  449. }
  450. virtual void processBeginDataset(const RtlFieldInfo * field)
  451. {
  452. UNSUPPORTED("Nested datasets");
  453. }
  454. virtual void processBeginRow(const RtlFieldInfo * field)
  455. {
  456. }
  457. virtual bool processNextRow(const RtlFieldInfo * field)
  458. {
  459. UNSUPPORTED("Nested datasets");
  460. }
  461. virtual void processEndSet(const RtlFieldInfo * field)
  462. {
  463. UNSUPPORTED("SET fields");
  464. }
  465. virtual void processEndDataset(const RtlFieldInfo * field)
  466. {
  467. UNSUPPORTED("Nested datasets");
  468. }
  469. virtual void processEndRow(const RtlFieldInfo * field)
  470. {
  471. }
  472. protected:
  473. void nextField(const RtlFieldInfo * field)
  474. {
  475. // NOTE - we could put support for looking up columns by name here, but for efficiency reasons we only support matching by position
  476. Rcpp::RObject colObject = frame[colIdx];
  477. Rcpp::List column = ::Rcpp::as<Rcpp::List>(colObject); // MORE - this can crash if wrong type came from R. But I can't work out how to test that
  478. Rcpp::RObject t = column[rowIdx];
  479. elem = t;
  480. colIdx++;
  481. }
  482. Rcpp::DataFrame frame;
  483. unsigned rowIdx;
  484. unsigned colIdx;
  485. Rcpp::RObject elem;
  486. };
  487. static size32_t getRowResult(RInside::Proxy &result, ARowBuilder &builder)
  488. {
  489. // To return a single row, we expect a dataframe (with 1 row)...
  490. Rcpp::DataFrame dFrame = ::Rcpp::as<Rcpp::DataFrame>(result); // Note that this will also accept (and convert) a list
  491. RRowBuilder myRRowBuilder(dFrame);
  492. const RtlTypeInfo *typeInfo = builder.queryAllocator()->queryOutputMeta()->queryTypeInfo();
  493. assertex(typeInfo);
  494. RtlFieldStrInfo dummyField("<row>", NULL, typeInfo);
  495. return typeInfo->build(builder, 0, &dummyField, myRRowBuilder);
  496. }
  497. // A R function that returns a dataset will return a RRowStream object that can be
  498. // interrogated to return each row of the result in turn
  499. class RRowStream : public CInterfaceOf<IRowStream>
  500. {
  501. public:
  502. RRowStream(RInside::Proxy &_result, IEngineRowAllocator *_resultAllocator)
  503. : dFrame(::Rcpp::as<Rcpp::DataFrame>(_result)),
  504. myRRowBuilder(dFrame)
  505. {
  506. resultAllocator.set(_resultAllocator);
  507. // A DataFrame is a list of columns
  508. // Each column is a vector (and all columns should be the same length)
  509. unsigned numColumns = dFrame.length();
  510. assertex(numColumns > 0);
  511. Rcpp::List col1 = dFrame[0];
  512. numRows = col1.length();
  513. idx = 0;
  514. }
  515. virtual const void *nextRow()
  516. {
  517. CriticalBlock b(RCrit);
  518. if (!resultAllocator)
  519. return NULL;
  520. if (idx >= numRows)
  521. {
  522. stop();
  523. return NULL;
  524. }
  525. RtlDynamicRowBuilder builder(resultAllocator);
  526. const RtlTypeInfo *typeInfo = builder.queryAllocator()->queryOutputMeta()->queryTypeInfo();
  527. assertex(typeInfo);
  528. RtlFieldStrInfo dummyField("<row>", NULL, typeInfo);
  529. myRRowBuilder.setRowIdx(idx);
  530. try
  531. {
  532. size32_t len = typeInfo->build(builder, 0, &dummyField, myRRowBuilder);
  533. idx++;
  534. return builder.finalizeRowClear(len);
  535. }
  536. catch (std::exception &E)
  537. {
  538. FAIL(E.what());
  539. }
  540. }
  541. virtual void stop()
  542. {
  543. resultAllocator.clear();
  544. }
  545. protected:
  546. Rcpp::DataFrame dFrame;
  547. Linked<IEngineRowAllocator> resultAllocator;
  548. RRowBuilder myRRowBuilder;
  549. unsigned numRows;
  550. unsigned idx;
  551. };
  552. // Each call to a R function will use a new REmbedFunctionContext object
  553. // This takes care of ensuring that the critsec is locked while we are executing R code,
  554. // and released when we are not
  555. class REmbedFunctionContext: public CInterfaceOf<IEmbedFunctionContext>
  556. {
  557. public:
  558. REmbedFunctionContext(RInside &_R, const char *options)
  559. : R(_R), block(RCrit), result(R_NilValue)
  560. {
  561. }
  562. ~REmbedFunctionContext()
  563. {
  564. }
  565. virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
  566. {
  567. return NULL;
  568. }
  569. virtual void paramWriterCommit(IInterface *writer)
  570. {
  571. }
  572. virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
  573. {
  574. }
  575. virtual bool getBooleanResult()
  576. {
  577. try
  578. {
  579. return ::Rcpp::as<bool>(result);
  580. }
  581. catch (std::exception &E)
  582. {
  583. FAIL(E.what());
  584. }
  585. }
  586. virtual void getDataResult(size32_t &__len, void * &__result)
  587. {
  588. try
  589. {
  590. std::vector<byte> vval = ::Rcpp::as<std::vector<byte> >(result);
  591. rtlStrToDataX(__len, __result, vval.size(), vval.data());
  592. }
  593. catch (std::exception &E)
  594. {
  595. FAIL(E.what());
  596. }
  597. }
  598. virtual double getRealResult()
  599. {
  600. try
  601. {
  602. return ::Rcpp::as<double>(result);
  603. }
  604. catch (std::exception &E)
  605. {
  606. FAIL(E.what());
  607. }
  608. }
  609. virtual __int64 getSignedResult()
  610. {
  611. try
  612. {
  613. return ::Rcpp::as<long int>(result); // Should really be long long, but RInside does not support that
  614. }
  615. catch (std::exception &E)
  616. {
  617. FAIL(E.what());
  618. }
  619. }
  620. virtual unsigned __int64 getUnsignedResult()
  621. {
  622. try
  623. {
  624. return ::Rcpp::as<unsigned long int>(result); // Should really be long long, but RInside does not support that
  625. }
  626. catch (std::exception &E)
  627. {
  628. FAIL(E.what());
  629. }
  630. }
  631. virtual void getStringResult(size32_t &__len, char * &__result)
  632. {
  633. try
  634. {
  635. std::string str = ::Rcpp::as<std::string>(result);
  636. rtlStrToStrX(__len, __result, str.length(), str.data());
  637. }
  638. catch (std::exception &E)
  639. {
  640. FAIL(E.what());
  641. }
  642. }
  643. virtual void getUTF8Result(size32_t &chars, char * &result)
  644. {
  645. UNSUPPORTED("Unicode/UTF8 results");
  646. }
  647. virtual void getUnicodeResult(size32_t &chars, UChar * &result)
  648. {
  649. UNSUPPORTED("Unicode/UTF8 results");
  650. }
  651. virtual void getSetResult(bool & __isAllResult, size32_t & __resultBytes, void * & __result, int _elemType, size32_t elemSize)
  652. {
  653. try
  654. {
  655. type_t elemType = (type_t) _elemType;
  656. __isAllResult = false;
  657. switch(elemType)
  658. {
  659. #define FETCH_ARRAY(type) \
  660. { \
  661. std::vector<type> vval = ::Rcpp::as< std::vector<type> >(result); \
  662. rtlStrToDataX(__resultBytes, __result, vval.size()*elemSize, (const void *) vval.data()); \
  663. }
  664. case type_boolean:
  665. {
  666. std::vector<bool> vval = ::Rcpp::as< std::vector<bool> >(result);
  667. size32_t size = vval.size();
  668. // Vector of bool is odd, and can't be retrieved via data()
  669. // Instead we need to iterate, I guess
  670. rtlDataAttr out(size);
  671. bool *outData = (bool *) out.getdata();
  672. for (std::vector<bool>::iterator iter = vval.begin(); iter < vval.end(); iter++)
  673. {
  674. *outData++ = *iter;
  675. }
  676. __resultBytes = size;
  677. __result = out.detachdata();
  678. break;
  679. }
  680. case type_int:
  681. /* if (elemSize == sizeof(signed char)) // rcpp does not seem to support...
  682. FETCH_ARRAY(signed char)
  683. else */ if (elemSize == sizeof(short))
  684. FETCH_ARRAY(short)
  685. else if (elemSize == sizeof(int))
  686. FETCH_ARRAY(int)
  687. else if (elemSize == sizeof(long)) // __int64 / long long does not work...
  688. FETCH_ARRAY(long)
  689. else
  690. rtlFail(0, "Rembed: Unsupported result type");
  691. break;
  692. case type_unsigned:
  693. if (elemSize == sizeof(byte))
  694. FETCH_ARRAY(byte)
  695. else if (elemSize == sizeof(unsigned short))
  696. FETCH_ARRAY(unsigned short)
  697. else if (elemSize == sizeof(unsigned int))
  698. FETCH_ARRAY(unsigned int)
  699. else if (elemSize == sizeof(unsigned long)) // __int64 / long long does not work...
  700. FETCH_ARRAY(unsigned long)
  701. else
  702. rtlFail(0, "Rembed: Unsupported result type");
  703. break;
  704. case type_real:
  705. if (elemSize == sizeof(float))
  706. FETCH_ARRAY(float)
  707. else if (elemSize == sizeof(double))
  708. FETCH_ARRAY(double)
  709. else
  710. rtlFail(0, "Rembed: Unsupported result type");
  711. break;
  712. case type_string:
  713. case type_varstring:
  714. {
  715. std::vector<std::string> vval = ::Rcpp::as< std::vector<std::string> >(result);
  716. size32_t numResults = vval.size();
  717. rtlRowBuilder out;
  718. byte *outData = NULL;
  719. size32_t outBytes = 0;
  720. if (elemSize != UNKNOWN_LENGTH)
  721. {
  722. outBytes = numResults * elemSize; // MORE - check for overflow?
  723. out.ensureAvailable(outBytes);
  724. outData = out.getbytes();
  725. }
  726. for (std::vector<std::string>::iterator iter = vval.begin(); iter < vval.end(); iter++)
  727. {
  728. size32_t lenBytes = (*iter).size();
  729. const char *text = (*iter).data();
  730. if (elemType == type_string)
  731. {
  732. if (elemSize == UNKNOWN_LENGTH)
  733. {
  734. out.ensureAvailable(outBytes + lenBytes + sizeof(size32_t));
  735. outData = out.getbytes() + outBytes;
  736. * (size32_t *) outData = lenBytes;
  737. rtlStrToStr(lenBytes, outData+sizeof(size32_t), lenBytes, text);
  738. outBytes += lenBytes + sizeof(size32_t);
  739. }
  740. else
  741. {
  742. rtlStrToStr(elemSize, outData, lenBytes, text);
  743. outData += elemSize;
  744. }
  745. }
  746. else
  747. {
  748. if (elemSize == UNKNOWN_LENGTH)
  749. {
  750. out.ensureAvailable(outBytes + lenBytes + 1);
  751. outData = out.getbytes() + outBytes;
  752. rtlStrToVStr(0, outData, lenBytes, text);
  753. outBytes += lenBytes + 1;
  754. }
  755. else
  756. {
  757. rtlStrToVStr(elemSize, outData, lenBytes, text); // Fixed size null terminated strings... weird.
  758. outData += elemSize;
  759. }
  760. }
  761. }
  762. __resultBytes = outBytes;
  763. __result = out.detachdata();
  764. break;
  765. }
  766. default:
  767. rtlFail(0, "REmbed: Unsupported result type");
  768. break;
  769. }
  770. }
  771. catch (std::exception &E)
  772. {
  773. FAIL(E.what());
  774. }
  775. }
  776. virtual IRowStream *getDatasetResult(IEngineRowAllocator * _resultAllocator)
  777. {
  778. try
  779. {
  780. return new RRowStream(result, _resultAllocator);
  781. }
  782. catch (std::exception &E)
  783. {
  784. FAIL(E.what());
  785. }
  786. }
  787. virtual byte * getRowResult(IEngineRowAllocator * _resultAllocator)
  788. {
  789. try
  790. {
  791. RtlDynamicRowBuilder rowBuilder(_resultAllocator);
  792. size32_t len = Rembed::getRowResult(result, rowBuilder);
  793. return (byte *) rowBuilder.finalizeRowClear(len);
  794. }
  795. catch (std::exception &E)
  796. {
  797. FAIL(E.what());
  798. }
  799. }
  800. virtual size32_t getTransformResult(ARowBuilder & builder)
  801. {
  802. try
  803. {
  804. return Rembed::getRowResult(result, builder);
  805. }
  806. catch (std::exception &E)
  807. {
  808. FAIL(E.what());
  809. }
  810. }
  811. virtual void bindBooleanParam(const char *name, bool val)
  812. {
  813. R[name] = val;
  814. }
  815. virtual void bindDataParam(const char *name, size32_t len, const void *val)
  816. {
  817. std::vector<byte> vval;
  818. const byte *cval = (const byte *) val;
  819. vval.assign(cval, cval+len);
  820. R[name] = vval;
  821. }
  822. virtual void bindFloatParam(const char *name, float val)
  823. {
  824. R[name] = val;
  825. }
  826. virtual void bindRealParam(const char *name, double val)
  827. {
  828. R[name] = val;
  829. }
  830. virtual void bindSignedSizeParam(const char *name, int size, __int64 val)
  831. {
  832. R[name] = (long int) val;
  833. }
  834. virtual void bindSignedParam(const char *name, __int64 val)
  835. {
  836. R[name] = (long int) val;
  837. }
  838. virtual void bindUnsignedSizeParam(const char *name, int size, unsigned __int64 val)
  839. {
  840. R[name] = (long int) val;
  841. }
  842. virtual void bindUnsignedParam(const char *name, unsigned __int64 val)
  843. {
  844. R[name] = (unsigned long int) val;
  845. }
  846. virtual void bindStringParam(const char *name, size32_t len, const char *val)
  847. {
  848. std::string s(val, len);
  849. R[name] = s;
  850. }
  851. virtual void bindVStringParam(const char *name, const char *val)
  852. {
  853. R[name] = val;
  854. }
  855. virtual void bindUTF8Param(const char *name, size32_t chars, const char *val)
  856. {
  857. rtlFail(0, "Rembed: Unsupported parameter type UTF8");
  858. }
  859. virtual void bindUnicodeParam(const char *name, size32_t chars, const UChar *val)
  860. {
  861. rtlFail(0, "Rembed: Unsupported parameter type UNICODE");
  862. }
  863. virtual void bindSetParam(const char *name, int _elemType, size32_t elemSize, bool isAll, size32_t totalBytes, void *setData)
  864. {
  865. if (isAll)
  866. rtlFail(0, "Rembed: Unsupported parameter type ALL");
  867. type_t elemType = (type_t) _elemType;
  868. int numElems = totalBytes / elemSize;
  869. switch(elemType)
  870. {
  871. #define BIND_ARRAY(type) \
  872. { \
  873. std::vector<type> vval; \
  874. const type *start = (const type *) setData; \
  875. vval.assign(start, start+numElems); \
  876. R[name] = vval; \
  877. }
  878. case type_boolean:
  879. BIND_ARRAY(bool)
  880. break;
  881. case type_int:
  882. /* if (elemSize == sizeof(signed char)) // No binding exists in rcpp
  883. BIND_ARRAY(signed char)
  884. else */ if (elemSize == sizeof(short))
  885. BIND_ARRAY(short)
  886. else if (elemSize == sizeof(int))
  887. BIND_ARRAY(int)
  888. else if (elemSize == sizeof(long)) // __int64 / long long does not work...
  889. BIND_ARRAY(long)
  890. else
  891. rtlFail(0, "Rembed: Unsupported parameter type");
  892. break;
  893. case type_unsigned:
  894. if (elemSize == sizeof(unsigned char))
  895. BIND_ARRAY(unsigned char)
  896. else if (elemSize == sizeof(unsigned short))
  897. BIND_ARRAY(unsigned short)
  898. else if (elemSize == sizeof(unsigned int))
  899. BIND_ARRAY(unsigned int)
  900. else if (elemSize == sizeof(unsigned long)) // __int64 / long long does not work...
  901. BIND_ARRAY(unsigned long)
  902. else
  903. rtlFail(0, "Rembed: Unsupported parameter type");
  904. break;
  905. case type_real:
  906. if (elemSize == sizeof(float))
  907. BIND_ARRAY(float)
  908. else if (elemSize == sizeof(double))
  909. BIND_ARRAY(double)
  910. else
  911. rtlFail(0, "Rembed: Unsupported parameter type");
  912. break;
  913. case type_string:
  914. case type_varstring:
  915. {
  916. std::vector<std::string> vval;
  917. const byte *inData = (const byte *) setData;
  918. const byte *endData = inData + totalBytes;
  919. while (inData < endData)
  920. {
  921. int thisSize;
  922. if (elemSize == UNKNOWN_LENGTH)
  923. {
  924. if (elemType==type_varstring)
  925. thisSize = strlen((const char *) inData) + 1;
  926. else
  927. {
  928. thisSize = * (size32_t *) inData;
  929. inData += sizeof(size32_t);
  930. }
  931. }
  932. else
  933. thisSize = elemSize;
  934. std::string s((const char *) inData, thisSize);
  935. vval.push_back(s);
  936. inData += thisSize;
  937. numElems++;
  938. }
  939. R[name] = vval;
  940. break;
  941. }
  942. default:
  943. rtlFail(0, "REmbed: Unsupported parameter type");
  944. break;
  945. }
  946. }
  947. virtual void bindRowParam(const char *name, IOutputMetaData & metaVal, byte *row)
  948. {
  949. // We create a single-row dataframe
  950. const RtlTypeInfo *typeInfo = metaVal.queryTypeInfo();
  951. assertex(typeInfo);
  952. RtlFieldStrInfo dummyField("<row>", NULL, typeInfo);
  953. RDataFrameHeaderBuilder headerBuilder;
  954. typeInfo->process(row, row, &dummyField, headerBuilder); // Sets up the R dataframe from the first ECL row
  955. Rcpp::List myList(headerBuilder.namevec.length());
  956. myList.attr("names") = headerBuilder.namevec;
  957. for (int i=0; i<myList.length(); i++)
  958. {
  959. Rcpp::List column(1);
  960. myList[i] = column;
  961. }
  962. RDataFrameAppender frameBuilder(myList);
  963. Rcpp::StringVector row_names(1);
  964. frameBuilder.setRowIdx(0);
  965. typeInfo->process(row, row, &dummyField, frameBuilder);
  966. row_names(0) = "1";
  967. myList.attr("class") = "data.frame";
  968. myList.attr("row.names") = row_names;
  969. R[name] = myList;
  970. }
  971. virtual void bindDatasetParam(const char *name, IOutputMetaData & metaVal, IRowStream * val)
  972. {
  973. const RtlTypeInfo *typeInfo = metaVal.queryTypeInfo();
  974. assertex(typeInfo);
  975. RtlFieldStrInfo dummyField("<row>", NULL, typeInfo);
  976. OwnedRoxieRowSet rows;
  977. loop
  978. {
  979. const byte *row = (const byte *) val->ungroupedNextRow();
  980. if (!row)
  981. break;
  982. rows.append(row);
  983. }
  984. const byte *firstrow = (const byte *) rows.item(0);
  985. RDataFrameHeaderBuilder headerBuilder;
  986. typeInfo->process(firstrow, firstrow, &dummyField, headerBuilder); // Sets up the R dataframe from the first ECL row
  987. Rcpp::List myList(headerBuilder.namevec.length());
  988. myList.attr("names") = headerBuilder.namevec;
  989. for (int i=0; i<myList.length(); i++)
  990. {
  991. Rcpp::List column(rows.length());
  992. myList[i] = column;
  993. }
  994. RDataFrameAppender frameBuilder(myList);
  995. Rcpp::StringVector row_names(rows.length());
  996. ForEachItemIn(idx, rows)
  997. {
  998. const byte * row = (const byte *) rows.item(idx);
  999. frameBuilder.setRowIdx(idx);
  1000. typeInfo->process(row, row, &dummyField, frameBuilder);
  1001. StringBuffer rowname;
  1002. rowname.append(idx+1);
  1003. row_names(idx) = rowname.str();
  1004. }
  1005. myList.attr("class") = "data.frame";
  1006. myList.attr("row.names") = row_names;
  1007. R[name] = myList;
  1008. }
  1009. virtual void importFunction(size32_t lenChars, const char *utf)
  1010. {
  1011. throwUnexpected();
  1012. }
  1013. virtual void compileEmbeddedScript(size32_t lenChars, const char *utf)
  1014. {
  1015. StringBuffer text(rtlUtf8Size(lenChars, utf), utf);
  1016. text.stripChar('\r');
  1017. func.assign(text.str());
  1018. }
  1019. virtual void callFunction()
  1020. {
  1021. try
  1022. {
  1023. result = R.parseEval(func);
  1024. }
  1025. catch (std::exception &E)
  1026. {
  1027. FAIL(E.what());
  1028. }
  1029. }
  1030. private:
  1031. RInside &R;
  1032. RInside::Proxy result;
  1033. std::string func;
  1034. CriticalBlock block;
  1035. };
  1036. class REmbedContext: public CInterfaceOf<IEmbedContext>
  1037. {
  1038. public:
  1039. virtual IEmbedFunctionContext *createFunctionContext(unsigned flags, const char *options)
  1040. {
  1041. return createFunctionContextEx(NULL, flags, options);
  1042. }
  1043. virtual IEmbedFunctionContext *createFunctionContextEx(ICodeContext * ctx, unsigned flags, const char *options)
  1044. {
  1045. return new REmbedFunctionContext(*queryGlobalState()->R, options);
  1046. }
  1047. virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
  1048. {
  1049. throwUnexpected();
  1050. }
  1051. };
  1052. extern IEmbedContext* getEmbedContext()
  1053. {
  1054. return new REmbedContext;
  1055. }
  1056. extern bool syntaxCheck(const char *script)
  1057. {
  1058. return true; // MORE
  1059. }
  1060. } // namespace