diff --git a/R/class.R b/R/class.R index ff95885..b9a75b3 100644 --- a/R/class.R +++ b/R/class.R @@ -312,11 +312,15 @@ setMethod("fetch", signature(res="JDBCResult", n="numeric"), def=function(res, n cts <- rep(0L, cols) for (i in 1:cols) { ct <- .jcall(res@md, "I", "getColumnType", i) - if (ct == -5 | ct ==-6 | (ct >= 2 & ct <= 8)) { + if (ct == 4 | ct == 5) { + l[[i]] <- integer() + cts[i] <- 2L + } else if (ct == -5 | ct ==-6 | (ct >= 2 & ct <= 8)) { l[[i]] <- numeric() cts[i] <- 1L - } else + } else { l[[i]] <- character() + } names(l)[i] <- .jcall(res@md, "S", "getColumnLabel", i) } rp <- res@pull @@ -328,13 +332,17 @@ setMethod("fetch", signature(res="JDBCResult", n="numeric"), def=function(res, n stride <- 32768L ## start fairly small to support tiny queries and increase later while ((nrec <- .jcall(rp, "I", "fetch", stride, block)) > 0L) { for (i in seq.int(cols)) - l[[i]] <- c(l[[i]], if (cts[i] == 1L) .jcall(rp, "[D", "getDoubles", i) else .jcall(rp, "[Ljava/lang/String;", "getStrings", i)) + l[[i]] <- c(l[[i]], if (cts[i] == 1L) .jcall(rp, "[D", "getDoubles", i) + else if(cts[i] == 2L) .jcall(rp, "[I", "getIntegers", i) + else .jcall(rp, "[Ljava/lang/String;", "getStrings", i)) if (nrec < stride) break stride <- 524288L # 512k } } else { nrec <- .jcall(rp, "I", "fetch", as.integer(n), block) - for (i in seq.int(cols)) l[[i]] <- if (cts[i] == 1L) .jcall(rp, "[D", "getDoubles", i) else .jcall(rp, "[Ljava/lang/String;", "getStrings", i) + for (i in seq.int(cols)) l[[i]] <- if (cts[i] == 1L) .jcall(rp, "[D", "getDoubles", i) + else if(cts[i] == 2L) .jcall(rp, "[I", "getIntegers", i) + else .jcall(rp, "[Ljava/lang/String;", "getStrings", i) } # as.data.frame is expensive - create it on the fly from the list attr(l, "row.names") <- c(NA_integer_, length(l[[1]])) @@ -349,7 +357,10 @@ setMethod("dbClearResult", "JDBCResult", setMethod("dbGetInfo", "JDBCResult", def=function(dbObj, ...) list(has.completed=TRUE), valueClass="list") ## this is not needed for recent DBI, but older implementations didn't provide default methods -setMethod("dbHasCompleted", "JDBCResult", def=function(res, ...) TRUE, valueClass="logical") +#setMethod("dbHasCompleted", "JDBCResult", def=function(res, ...) TRUE, valueClass="logical") +setMethod("dbHasCompleted", "JDBCResult", def=function(res, ...) + .jcall(res@jr, "Z", "isClosed"), + valueClass="logical") setMethod("dbColumnInfo", "JDBCResult", def = function(res, ...) { cols <- .jcall(res@md, "I", "getColumnCount") @@ -359,7 +370,9 @@ setMethod("dbColumnInfo", "JDBCResult", def = function(res, ...) { l$name[i] <- .jcall(res@md, "S", "getColumnLabel", i) l$field.type[i] <- .jcall(res@md, "S", "getColumnTypeName", i) ct <- .jcall(res@md, "I", "getColumnType", i) - l$data.type[i] <- if (ct == -5 | ct ==-6 | (ct >= 2 & ct <= 8)) "numeric" else "character" + l$data.type[i] <- if(ct == 4 | ct == 5) "integer" + else if (ct == -5 | ct ==-6 | (ct >= 2 & ct <= 8)) "numeric" + else "character" l$field.name[i] <- .jcall(res@md, "S", "getColumnName", i) } as.data.frame(l, row.names=1:cols) diff --git a/java/JDBCBatchExecute.java b/java/JDBCBatchExecute.java index 55073e1..13eed29 100644 --- a/java/JDBCBatchExecute.java +++ b/java/JDBCBatchExecute.java @@ -12,6 +12,10 @@ public class JDBCBatchExecute { static final int T_DOUBLE = 1; static final int T_INT = 2; static final int T_STRING = 3; + + public static final double NA_double = Double.longBitsToDouble(0x7ff00000000007a2L); + public static final int NA_integer = -2147483648; + public JDBCBatchExecute(PreparedStatement stat, int n) { cache = new Object[n]; @@ -48,10 +52,16 @@ public void execute(int maxBatch) throws java.sql.SQLException { while (i < ptr) { if (types[i] == T_DOUBLE) { double val = ((double[])(cache[i]))[l]; // FIXME: NA? - s.setDouble(i + 1, val); + if(Double.isNaN(val)) + s.setNull(i+1, java.sql.Types.DOUBLE); + else + s.setDouble(i + 1, val); } else if (types[i] == T_INT) { int val = ((int[])(cache[i]))[l]; // FIXME: NA? - s.setInt(i + 1, val); + if(val == NA_integer) + s.setNull(i+1, java.sql.Types.INTEGER); + else + s.setInt(i + 1, val); } else if(types[i] == T_STRING) { String val = ((String[])(cache[i]))[l]; if (val == null) diff --git a/java/JDBCResultPull.java b/java/JDBCResultPull.java index 3c8c062..a7f5fa5 100644 --- a/java/JDBCResultPull.java +++ b/java/JDBCResultPull.java @@ -7,8 +7,10 @@ public class JDBCResultPull { public static final int CT_STRING = 0; /** column type: numeric (retrieved as doubles) */ public static final int CT_NUMERIC = 1; + public static final int CT_INTEGER = 2; /** NA double value */ public static final double NA_double = Double.longBitsToDouble(0x7ff00000000007a2L); + public static final int NA_integer = -2147483648; /** active result set */ ResultSet rs; @@ -53,7 +55,13 @@ public JDBCResultPull(ResultSet rs, int cTypes[]) { public void setCapacity(int atMost) { if (capacity != atMost) { for (int i = 0; i < cols; i++) - data[i] = (cTypes[i] == CT_NUMERIC) ? (Object)new double[atMost] : (Object)new String[atMost]; + //data[i] = (cTypes[i] == CT_NUMERIC) ? (Object)new double[atMost] : (Object)new String[atMost]; + if(cTypes[i] == CT_NUMERIC) + data[i] = (Object)new double[atMost]; + else if(cTypes[i] == CT_INTEGER) + data[i] = (Object)new int[atMost]; + else + data[i] = (Object)new String[atMost]; capacity = atMost; } } @@ -80,6 +88,10 @@ public int fetch(int atMost, int fetchSize) throws java.sql.SQLException { double val = rs.getDouble(i + 1); if (rs.wasNull()) val = NA_double; ((double[])data[i])[count] = val; + } else if(cTypes[i] == CT_INTEGER) { + int val = rs.getInt(i + 1); + if (rs.wasNull()) val = NA_integer; + ((int[])data[i])[count] = val; } else ((String[])data[i])[count] = rs.getString(i + 1); count++; @@ -119,4 +131,13 @@ public double[] getDoubles(int column) { if (count > 0) System.arraycopy(a, 0, b, 0, count); return b; } -} \ No newline at end of file + + public int[] getIntegers(int column) { + int[] a = (int[]) data[column - 1]; + if(count == a.length) return a; + + int[] b = new int[count]; + if(count > 0) System.arraycopy(a, 0, b, 0, count); + return b; + } +}