2

So basically, I am using Java, JRI (R for Java) and RJDBC (with the help of JRI), which all work out pretty well. Now, I want to make my program as foolproof as possible. Let's say, that the string SQL_command is some kind of rubbish and not really a valid SQL-statement. In that case...

    re.eval("sql_data <- dbGetQuery(conn, \"" + SQL_command + "\")");

...should go wrong. My thinking goes like this: If that R command fails, there will be some kind of output in R. If everythings correct, no output. But how can I capture that possible output?

Keep in mind, that my problem is more about how to catch invalid R statements, so any other suggestion for a possible solution is also appreciated. The R output is not necessarily important, but it may be interesting anyway.

Thanks in advance!

The_F
  • 45
  • 4
  • I don't get this... What kind of capture? re.capture.output() doesn't exist. If you mean inside of R... Didn't really help. How can I use "last.warning"? "cat(last.warning)"? – The_F Oct 12 '14 at 22:03
  • Okay, well that's why it's a comment and not an answer. Just a suggestion. – Rich Scriven Oct 12 '14 at 22:04

2 Answers2

2

I'd suggest to catch the (possible) exceptions due to R code directly in R. So, if I suspect that a command could give an error, I'd use the try function in R. Something along this lines:

       REXP y = re.eval("sql_data <- try(dbGetQuery(conn, \"" + SQL_command + "\"),silent=TRUE)");
       REXP x = re.eval("class(sql_data)");
       if ((x.asString()).equals("try-error")) {
          System.out.println(y.asString());
          // do something to catch the exception
       } else {
         // do normal stuff
       }

In this way you can also display the R error.

Here a little reproducible (aside from the database credentials) code that tries to execute first the valid query statement and then the invalid one.

      import java.io.*;
      import org.rosuda.JRI.*;
      public class Prova {
         public static void main(String[] args) {
           String[] commands = {"a<-try(dbGetQuery(conn,'show tables'))","a<-try(dbGetQuery(conn,'SS'))"};
           Rengine re=new Rengine (new String [] {"--vanilla"}, false, null);
           re.eval("require(RMySQL)");
           re.eval("conn<-dbConnect(MySQL(),user='xxx',password='xxx',dbname='xxx')");
           for (int i=0;i<2;i++) {
             REXP y = re.eval(commands[i]);
             REXP x = re.eval("class(a)");
             if ((x.asString()).equals("try-error")) {
               System.out.println(y.asString());
             } else {
               System.out.println(x.asString());
             }
           }
           re.end();
         }
      }

The output:

   data.frame
   Error in mysqlExecStatement(conn, statement, ...) : 
     RS-DBI driver: (could not run statement: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SS' at line 1)
nicola
  • 24,005
  • 3
  • 35
  • 56
  • I tried this, but it didn't work. By making an object out of the re.eval()-command, it just stops doing whatever it did, whenever the R command in brackets fails. In other words: REXP x = re.eval(SOME_WRONG_R_CODE); skips everything. – The_F Oct 12 '14 at 20:19
  • Can you provide exactly the `SQL_command` you are giving to R? – nicola Oct 12 '14 at 20:26
  • sql_data <- dbGetQuery(conn, "SS") – The_F Oct 12 '14 at 20:31
  • I forgot an `asString()` after `getAttribute`. I'm gonna edit my answer. Let me see if it works. – nicola Oct 12 '14 at 20:43
  • It doesn't, because it skips everything after I store re.eval into an REXP-object. That doesn't happen though, if the re.eval command is executed correctly. Weird... – The_F Oct 12 '14 at 20:47
  • I re-edited my answer, providing a reproducible example that works for me. Let me know. – nicola Oct 12 '14 at 20:59
  • I was oblivious of the "try()" statement. It works perfect, thank you soooo much! – The_F Oct 12 '14 at 21:35
0

According to the documentation for the org.rosuda.JRI.Rengine.eval(String) method, null will be returned if something went wrong. The method does not throw any type of Exception so it doesn't seem to offer any way of determining the cause of a problem.

The org.rosuda.REngine.parseAndEval(String) method does throw a couple of Exception types, REngineException and REXPMismatchException which might offer more explanation of failure, but the documentation is not clear on exactly why and when these will be thrown.

So it might be the case that the best you can do is to check for a null return value.

Bobulous
  • 12,967
  • 4
  • 37
  • 68
  • I don't have that parseAndEval()-Method. re.parseAndEval(String) doesn't exist according to Eclipse. – The_F Oct 12 '14 at 20:49
  • Notice that the `parseAndEval` method is in a totally different class (with almost exactly the same name) in a different package. So your `re` object will not be able to call that method. – Bobulous Oct 12 '14 at 20:55