Changeset: 3a53a2b51cba for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3a53a2b51cba
Modified Files:
        monetdb5/extras/rapi/rapi.R
        monetdb5/extras/rapi/rapi.c
        monetdb5/extras/rapi/rapi.h
        sql/backends/monet5/Tests/All
        sql/backends/monet5/Tests/rapi05.sql
Branch: RIntegration
Log Message:

R API: Bugfixes, moved R package directory into dbfarm, rewrote init code, 
better error messages on return type mismatches, test output


diffs (truncated from 398 to 300 lines):

diff --git a/monetdb5/extras/rapi/rapi.R b/monetdb5/extras/rapi/rapi.R
--- a/monetdb5/extras/rapi/rapi.R
+++ b/monetdb5/extras/rapi/rapi.R
@@ -20,20 +20,22 @@
 # auto-install packages by intercepting library()
 .library.original <- library
 
-library <- function(package, help, pos = 2, lib.loc = NULL, character.only = 
FALSE, 
+# configure our own library path in the dbfarm
+.libPaths(.rapi.libdir)
+
+library <- function(package, help, pos = 2, lib.loc = .libPaths(), 
character.only = FALSE, 
     logical.return = FALSE, warn.conflicts = TRUE, quietly = FALSE, 
     verbose = getOption("verbose")) {
 
        package <- as.character(substitute(package))
        if (!(package %in% installed.packages()[,"Package"])) 
-               install.packages(package,repos=c("http://cran.rstudio.com/";))
+               
install.packages(package,repos=c("http://cran.rstudio.com/";),lib=.rapi.libdir)
        
        
.library.original(package,help,pos,lib.loc,character.only=T,logical.return,warn.conflicts,quietly)
 }
 
 # do not re-install existing packages if install.packages() is called
 install.packages.original <- install.packages
-# TODO how to check version etc?
 
 # redirect default graphics device to PDF
 options(device="pdf")
diff --git a/monetdb5/extras/rapi/rapi.c b/monetdb5/extras/rapi/rapi.c
--- a/monetdb5/extras/rapi/rapi.c
+++ b/monetdb5/extras/rapi/rapi.c
@@ -41,6 +41,9 @@
 
 // other headers
 #include <string.h>
+#include <sys/stat.h>
+
+#define SOME_CONFIG_VAR_FOR_RHOME "/usr/lib64/R"
 
 #define BAT_TO_INTSXP(bat,tpe,retsxp) { \
        tpe v;  size_t j; \
@@ -113,67 +116,120 @@
 // The R-environment should be single threaded, calling for some protective 
measures.
 static MT_Lock rapiLock;
 static int rapiInitialized = FALSE;
+static char* rtypenames[] = { "NIL", "SYM", "LIST", "CLO", "ENV", "PROM",
+               "LANG", "SPECIAL", "BUILTIN", "CHAR", "LGL", "unknown", 
"unknown",
+               "INT", "REAL", "CPLX", "STR", "DOT", "ANY", "VEC", "EXPR", 
"BCODE",
+               "EXTPTR", "WEAKREF", "RAW", "S4" };
 
-void writeConsole(const char * buf, int buflen) {
-       (void) buflen;
-       THRprintf(GDKout, "%s", buf);
-       fprintf(stderr, "%s", buf);
+// helper function to translate R TYPEOF() return values to something readable
+char* rtypename(int rtypeid) {
+       if (rtypeid < 0 || rtypeid > 25) {
+               return "unknown";
+       } else
+               return rtypenames[rtypeid];
 }
+
 void writeConsoleEx(const char * buf, int buflen, int foo) {
        (void) buflen;
        (void) foo;
-       THRprintf(GDKout, "%s", buf);
+       // TODO: do we really want to write this to the console?
+       THRprintf(GDKout, "# %s", buf);
+}
+
+void writeConsole(const char * buf, int buflen) {
+       writeConsoleEx(buf,buflen,-42);
 }
 
 static int RAPIinitialize(void) {
-       char *rargv[] = { "whatever", "--quiet", "--no-save", 
"--no-restore-data" };
-       int rargc = 4;
-       int evalErr;
-       ParseStatus status;
-       char rlibs[BUFSIZ];
-       char rapiinclude[BUFSIZ];
        MT_lock_init(&rapiLock, "rapi_lock");
 
-       // adapted from Rinit.c (JRI package)
-       if (!getenv("R_HOME")) {
-               return 1;
-       }
+       // set R_HOME for packages etc.
+       setenv("R_HOME", SOME_CONFIG_VAR_FOR_RHOME, TRUE);
 
-       // TODO: put this into dbfarm
-       snprintf(rlibs, BUFSIZ, "%s%c%s%c%s%c%s",
-       LOCALSTATEDIR, DIR_SEP, "monetdb5", DIR_SEP, "rapi",
-       DIR_SEP, "libs");
-       setenv("R_LIBS_USER", rlibs, TRUE);
+#ifdef _RAPI_DEBUG_
+       printf("# R libraries installed in %s\n",rlibs);
+#endif
 
 #ifdef RIF_HAS_RSIGHAND
        R_SignalHandlers=0;
 #endif
+       // set some command line arguments
        {
-               int stat = Rf_initialize_R(rargc, rargv);
+               structRstart rp;
+               Rstart Rp = &rp;
+               char *rargv[] = { "R" ,"--vanilla"};
+               int stat;
+
+               R_DefParams(Rp);
+               Rp->R_Slave = TRUE;
+               Rp->R_Quiet = TRUE;
+               Rp->R_Interactive = FALSE;
+               Rp->R_Verbose = FALSE;
+               Rp->LoadSiteFile = FALSE;
+               Rp->RestoreAction = SA_NORESTORE;
+               Rp->SaveAction = SA_NOSAVE;
+               Rp->NoRenviron = TRUE;
+               stat = Rf_initialize_R(2, rargv);
                if (stat < 0) {
                        return 2;
                }
+               R_SetParams(Rp);
        }
 
+       // yes, again...
 #ifdef RIF_HAS_RSIGHAND
        R_SignalHandlers=0;
 #endif
-       /* disable stack checking, because threads will thow it off */
+
+       /* disable stack checking, because threads will throw it off */
        R_CStackLimit = (uintptr_t) -1;
-       R_Interactive = FALSE;
-       ptr_R_WriteConsole = writeConsole;
-       ptr_R_WriteConsoleEx = writeConsoleEx;
        R_Outputfile = NULL;
        R_Consolefile = NULL;
 
+       ptr_R_WriteConsoleEx = writeConsoleEx;
+       ptr_R_WriteConsole = writeConsole;
+
+       ptr_R_ReadConsole = NULL;
+
        // big boy here
        setup_Rmainloop();
 
-       // run the R environment initialization script rapi.R
-       snprintf(rapiinclude, BUFSIZ, "source(\"%s\")",
-                       locate_file("rapi", ".R", 0));
-       R_tryEval(VECTOR_ELT(R_ParseVector(
-       mkString(rapiinclude), 1, &status, R_NilValue), 0), R_GlobalEnv, 
&evalErr);
+       {
+               int evalErr;
+               ParseStatus status;
+               char rlibs[BUFSIZ];
+               char rapiinclude[BUFSIZ];
+               SEXP librisexp;
+               struct stat sb;
+
+               // r library folder, create if not exists
+               snprintf(rlibs, BUFSIZ, "%s%c%s", GDKgetenv("gdk_dbpath"), 
DIR_SEP,
+                               "rapi_packages");
+
+               if (stat(rlibs, &sb) != 0) {
+                       if (mkdir(rlibs, S_IRWXU) != 0) {
+                               return 4;
+                       }
+               }
+
+               PROTECT(librisexp = allocVector(STRSXP, 1));
+               SET_STRING_ELT(librisexp, 0, mkChar(rlibs));
+               Rf_defineVar(Rf_install(".rapi.libdir"),librisexp, R_GlobalEnv);
+               UNPROTECT(1);
+
+               // run rapi.R environment setup script
+               snprintf(rapiinclude, BUFSIZ, "source(\"%s\")",
+                               locate_file("rapi", ".R", 0));
+               R_tryEvalSilent(
+                               VECTOR_ELT(
+                                               
R_ParseVector(mkString(rapiinclude), 1, &status,
+                                                               R_NilValue), 
0), R_GlobalEnv, &evalErr);
+
+               // of course the script may contain errors as well
+               if (evalErr != FALSE) {
+                       return 5;
+               }
+       }
 
        rapiInitialized++;
        return 0;
@@ -187,7 +243,7 @@ str RAPIparser(int *ret, str *rcall) {
        (void) R_ParseVector(mkString(*rcall), INT_MAX, &status, R_NilValue);
        if (status != PARSE_OK)
                msg = createException(MAL, "rapi.eval", "%s", *rcall);
-       free(*rcall);
+       free(*rcall); // why free here? This is someone else's job, no?
        return msg;
 }
 
@@ -221,22 +277,18 @@ str RAPIeval(Client cntxt, MalBlkPtr mb,
                throw(MAL, "rapi.eval", MAL_MALLOC_FAIL);
        }
 
+       // we don't need no context, but the compiler needs us to touch it (...)
+       (void) cntxt;
+
        /* startup internal R environment if needed */
        if (!rapiInitialized) {
                initstatus = RAPIinitialize();
                if (initstatus != 0) {
-                       msg = createException(MAL, "rapi.eval",
-                                       "failed to initialize R environment 
(%i)", initstatus);
-                       goto wrapup;
+                       throw(MAL, "rapi.eval", "failed to initialise R 
environment (%i)",
+                                       initstatus);
                }
        }
 
-#ifdef _RAPI_DEBUG_
-       mnstr_printf(cntxt->fdout, "# User R expression: %s\n", exprStr);
-#else
-       (void) cntxt;
-#endif
-
        MT_lock_set(&rapiLock, "rapi.evaluate");
        env = PROTECT(eval(lang1(install("new.env")),R_GlobalEnv));
        assert(env != NULL);
@@ -313,7 +365,7 @@ str RAPIeval(Client cntxt, MalBlkPtr mb,
                        break;
                default:
                        // no clue what type to consider
-                       msg = createException(MAL, "rapi.eval", "unknown 
argument type");
+                       msg = createException(MAL, "rapi.eval", "unknown 
argument type ");
                        goto wrapup;
                }
                BBPreleaseref(b->batCacheid);
@@ -339,24 +391,20 @@ str RAPIeval(Client cntxt, MalBlkPtr mb,
                        "ret <- 
as.data.frame((function(%s){%s})(%s),nm=NA,stringsAsFactors=F)\n",
                        argnames, exprStr, argnames);
 
-#ifdef _RAPI_DEBUG_
-       mnstr_printf(cntxt->fdout, "# Executed R expression %s\n", rcall);
-#endif
+       x = R_ParseVector(mkString(rcall), 1, &status, R_NilValue);
+       assert(LENGTH(x) == 1);
 
-       x = R_ParseVector(mkString(rcall), INT_MAX, &status, R_NilValue);
        if (status != PARSE_OK) {
-               msg = createException(MAL, "rapi.eval", "%s", exprStr);
+               msg = createException(MAL, "rapi.eval",
+                               "Error parsing R expression '%s'. ", exprStr);
                goto wrapup;
        }
 
-       /* parsing creates a separate call for each statement, since our r code 
can consist of multiple statements, we need to evaluate each vector entry */
-       if (LENGTH(x) != 1) {
-               msg = createException(MAL, "rapi.eval", "%s", exprStr);
-               goto wrapup;
-       }
        retval = R_tryEval(VECTOR_ELT(x, 0), env, &evalErr);
        if (evalErr != FALSE) {
-               msg = createException(MAL, "rapi.eval", "%s", exprStr);
+               msg = createException(MAL, "rapi.eval",
+                               "Error running R expression '%s'. Error 
message: %s", exprStr,
+                               R_curErrorBuf());
                goto wrapup;
        }
 
@@ -376,7 +424,7 @@ str RAPIeval(Client cntxt, MalBlkPtr mb,
                int *ret = (int *) getArgReference(stk, pci, i);
                cnt = (BUN) ret_rows;
 
-               // check if return type is indeed a BAT
+               // check if MAL return type is indeed a BAT
                if (!isaBatType(getArgType(mb,pci,i))) {
                        msg = createException(MAL, "rapi.eval",
                                        "I only like BAT return types");
@@ -387,9 +435,10 @@ str RAPIeval(Client cntxt, MalBlkPtr mb,
                switch (bat_type) {
                case TYPE_int: {
                        if (!IS_INTEGER(ret_col)) {
-                               msg = createException(MAL, "rapi.eval",
-                                               "wrong R column type for column 
%d, expected integer",
-                                               i);
+                               msg =
+                                               createException(MAL, 
"rapi.eval",
+                                                               "wrong R column 
type for column %d, expected INTeger, got %s.",
+                                                               i, 
rtypename(TYPEOF(ret_col)));
                                goto wrapup;
                        }
                        SXP_TO_BAT(int, INTEGER_POINTER, *p==NA_INTEGER);
@@ -397,30 +446,32 @@ str RAPIeval(Client cntxt, MalBlkPtr mb,
                }
                case TYPE_lng: {
                        if (!IS_INTEGER(ret_col)) {
-                               msg = createException(MAL, "rapi.eval",
-                                               "wrong R column type for column 
%d, expected integer",
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to