Changeset: 21143fb53227 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=21143fb53227 Modified Files: clients/R/MonetDB.R/DESCRIPTION clients/R/MonetDB.R/NEWS clients/R/MonetDB.R/R/dbi.R clients/R/MonetDB.R/R/mapi.R clients/R/MonetDB.R/src/mapisplit.c clients/R/Tests/dbi.R Branch: default Log Message:
R Connector: Progress bar, MAPI parser overhaul diffs (truncated from 487 to 300 lines): diff --git a/clients/R/MonetDB.R/DESCRIPTION b/clients/R/MonetDB.R/DESCRIPTION --- a/clients/R/MonetDB.R/DESCRIPTION +++ b/clients/R/MonetDB.R/DESCRIPTION @@ -1,5 +1,5 @@ Package: MonetDB.R -Version: 0.9.6 +Version: 0.9.7 Title: Connect MonetDB to R Authors@R: c(person("Hannes Muehleisen", role = c("aut", "cre"),email = "han...@cwi.nl"), person("Thomas Lumley", role = "ctb"), diff --git a/clients/R/MonetDB.R/NEWS b/clients/R/MonetDB.R/NEWS --- a/clients/R/MonetDB.R/NEWS +++ b/clients/R/MonetDB.R/NEWS @@ -1,3 +1,9 @@ +0.9.7 +- monetdb.read.csv TODO (thanks, Duncan) +- dbWriteTable encoding checks TODO (thanks, Anthony) +- deprecated nrows parameter to monetdb.read.csv, not neccessary any more because of upgrades to MonetDB +- added query progress bar (counting MAL statements) for MonetDB releases following Oct2014, enable with options(monetdb.profile=T) + 0.9.6 - Fixed non-ASCII character handling (thanks, Roman!) - Fully removed C-based socket code diff --git a/clients/R/MonetDB.R/R/dbi.R b/clients/R/MonetDB.R/R/dbi.R --- a/clients/R/MonetDB.R/R/dbi.R +++ b/clients/R/MonetDB.R/R/dbi.R @@ -125,6 +125,15 @@ setMethod("dbConnect", "MonetDBDriver", message("MonetDB: Switching to single-threaded query execution.") dbSendQuery(conn, "set optimizer='sequential_pipe'") } + + # enable profiler, we use a MAL connection for this + if (getOption("monetdb.profile", F)) { + msocket <- .mapiConnect(host, port, timeout) + .mapiAuthenticate(msocket, dbname, user, password, language="mal") + .profiler_enable(msocket) + .mapiDisconnect(msocket); + message("Enabled profiler") + } return(conn) @@ -222,64 +231,64 @@ setMethod("dbReadTable", "MonetDBConnect setMethod("dbSendQuery", signature(conn="MonetDBConnection", statement="character"), def=function(conn, statement, ..., list=NULL, async=FALSE) { - if(!is.null(list) || length(list(...))){ - if (length(list(...))) statement <- .bindParameters(statement, list(...)) - if (!is.null(list)) statement <- .bindParameters(statement, list) - } - conn@connenv$exception <- list() - env <- NULL - # Auto-convert? - # statement <- enc2utf8(statement) - if (getOption("monetdb.debug.query", F)) message("QQ: '", statement, "'") - resp <- .mapiParseResponse(.mapiRequest(conn, paste0("s", statement, "\n;"), async=async)) - - env <- new.env(parent=emptyenv()) - - if (resp$type == Q_TABLE) { - # we have to pass this as an environment to make conn object available to result for fetching - env$success = TRUE - env$conn <- conn - env$data <- resp$tuples - resp$tuples <- NULL # clean up - env$info <- resp - env$delivered <- 0 - env$query <- statement - env$open <- TRUE - } - if (resp$type == Q_UPDATE || resp$type == Q_CREATE || resp$type == MSG_ASYNC_REPLY) { - env$success = TRUE - env$conn <- conn - env$query <- statement - env$info <- resp + if(!is.null(list) || length(list(...))){ + if (length(list(...))) statement <- .bindParameters(statement, list(...)) + if (!is.null(list)) statement <- .bindParameters(statement, list) + } + conn@connenv$exception <- list() + env <- NULL + if (getOption("monetdb.debug.query", F)) message("QQ: '", statement, "'") + # the actual request + mresp <- .mapiRequest(conn, paste0("s", statement, "\n;"), async=async) + resp <- .mapiParseResponse(mresp) - } - if (resp$type == MSG_MESSAGE) { - env$success = FALSE - env$conn <- conn - env$query <- statement - env$info <- resp - env$message <- resp$message - } - - if (!env$success) { - sp <- strsplit(env$message, "!", fixed=T)[[1]] - # truncate statement to not hide actual error message - if (nchar(statement) > 100) { statement <- paste0(substring(statement, 1, 100), "...") } - if (length(sp) == 3) { - errno <- sp[[2]] - errmsg <- sp[[3]] - conn@connenv$exception <- list(errNum=errno, errMsg=errmsg) - stop("Unable to execute statement '", statement, "'.\nServer says '", errmsg, "' [#", - errno, "].") - } - else { - conn@connenv$exception <- list(errNum=NA, errMsg=env$message) - stop("Unable to execute statement '", statement, "'.\nServer says '", env$message, "'.") - } - } - - return(new("MonetDBResult", env=env)) - }) + env <- new.env(parent=emptyenv()) + + if (resp$type == Q_TABLE) { + # we have to pass this as an environment to make conn object available to result for fetching + env$success = TRUE + env$conn <- conn + env$data <- resp$tuples + resp$tuples <- NULL # clean up + env$info <- resp + env$delivered <- 0 + env$query <- statement + env$open <- TRUE + } + if (resp$type == Q_UPDATE || resp$type == Q_CREATE || resp$type == MSG_ASYNC_REPLY) { + env$success = TRUE + env$conn <- conn + env$query <- statement + env$info <- resp + + } + if (resp$type == MSG_MESSAGE) { + env$success = FALSE + env$conn <- conn + env$query <- statement + env$info <- resp + env$message <- resp$message + } + + if (!env$success) { + sp <- strsplit(env$message, "!", fixed=T)[[1]] + # truncate statement to not hide actual error message + if (nchar(statement) > 100) { statement <- paste0(substring(statement, 1, 100), "...") } + if (length(sp) == 3) { + errno <- sp[[2]] + errmsg <- sp[[3]] + conn@connenv$exception <- list(errNum=errno, errMsg=errmsg) + stop("Unable to execute statement '", statement, "'.\nServer says '", errmsg, "' [#", + errno, "].") + } + else { + conn@connenv$exception <- list(errNum=NA, errMsg=env$message) + stop("Unable to execute statement '", statement, "'.\nServer says '", env$message, "'.") + } + } + + return(new("MonetDBResult", env=env)) + }) @@ -323,7 +332,7 @@ setMethod("dbWriteTable", "MonetDBConnec if (length(value[[1]])) { if (csvdump) { tmp <- tempfile(fileext = ".csv") - write.table(value, tmp, sep = ",", quote = TRUE,row.names = FALSE, col.names = FALSE,na="") + write.table(value, tmp, sep = ",", quote = TRUE, row.names = FALSE, col.names = FALSE,na="") dbSendQuery(conn, paste0("COPY ",format(nrow(value), scientific=FALSE)," RECORDS INTO ", qname, " FROM '", tmp, "' USING DELIMITERS ',','\\n','\"' NULL AS ''")) file.remove(tmp) @@ -528,7 +537,7 @@ setMethod("dbFetch", signature(res="Mone # convert tuple string vector into matrix so we can access a single column efficiently # call to a faster C implementation for the annoying task of splitting everyting into fields - parts <- .Call("mapiSplit", res@env$data[1:n], as.integer(info$cols), PACKAGE=C_LIBRARY) + parts <- .Call("mapi_split", res@env$data[1:n], as.integer(info$cols), PACKAGE=C_LIBRARY) # convert values column by column for (j in seq.int(info$cols)) { @@ -610,13 +619,17 @@ setMethod("dbGetInfo", "MonetDBResult", has.completed=dbHasCompleted(dbObj), is.select=TRUE)) }, valueClass="list") -# copied from RMonetDB, no java-specific things in here... -monet.read.csv <- monetdb.read.csv <- function(conn, files, tablename, nrows, header=TRUE, +# adapted from RMonetDB, no java-specific things in here... +monet.read.csv <- monetdb.read.csv <- function(conn, files, tablename, nrows=NA, header=TRUE, locked=FALSE, na.strings="", nrow.check=500, delim=",", newline="\\n", quote="\"", ...){ if (length(na.strings)>1) stop("na.strings must be of length 1") headers <- lapply(files, read.csv, sep=delim, na.strings=na.strings, quote=quote, nrows=nrow.check, ...) + + if (!missing(nrows)) { + warning("monetdb.read.csv(): nrows parameter is not neccessary any more and deprecated.") + } if (length(files)>1){ nn <- sapply(headers, ncol) @@ -631,19 +644,18 @@ monet.read.csv <- monetdb.read.csv <- fu delimspec <- paste0("USING DELIMITERS '", delim, "','", newline, "','", quote, "'") - if(header || !missing(nrows)){ - if (length(nrows)==1) nrows <- rep(nrows, length(files)) + if(header){ for(i in seq_along(files)) { thefile <- normalizePath(files[i]) - dbSendUpdate(conn, paste("COPY", format(nrows[i], scientific=FALSE), "OFFSET 2 RECORDS INTO", - tablename, "FROM", paste("'", thefile, "'", sep=""), delimspec, "NULL as", paste("'", - na.strings[1], "'", sep=""), if(locked) "LOCKED")) + dbSendUpdate(conn, paste("COPY OFFSET 2 INTO", + tablename, "FROM", paste("'", thefile, "'", sep=""), delimspec, "NULL as", paste("'", + na.strings[1], "'", sep=""), if(locked) "LOCKED")) } } else { for(i in seq_along(files)) { thefile <- normalizePath(files[i]) dbSendUpdate(conn, paste0("COPY INTO ", tablename, " FROM ", paste("'", thefile, "'", sep=""), - delimspec, "NULL as ", paste("'", na.strings[1], "'", sep=""), if(locked) " LOCKED ")) + delimspec, "NULL as ", paste("'", na.strings[1], "'", sep=""), if(locked) " LOCKED ")) } } dbGetQuery(conn, paste("select count(*) from", tablename)) diff --git a/clients/R/MonetDB.R/R/mapi.R b/clients/R/MonetDB.R/R/mapi.R --- a/clients/R/MonetDB.R/R/mapi.R +++ b/clients/R/MonetDB.R/R/mapi.R @@ -315,7 +315,7 @@ REPLY_SIZE <- 100 # Apparently, -1 me protocol <- redirect[[1]][1] if (protocol == "merovingian") { # retry auth on same connection, we will get a new challenge - .mapiAuthenticate(con, dbname, user, password, endhashfunc) + .mapiAuthenticate(con, dbname, user, password, endhashfunc, language) } if (protocol == "monetdb") { stop("Forwarding to another server (", link, ") not supported.") @@ -327,8 +327,10 @@ REPLY_SIZE <- 100 # Apparently, -1 me } else { if (getOption("monetdb.debug.mapi", F)) message("II: Authentication successful.") # setting some server parameters...not sure if this should happen here - .mapiWrite(con, paste0("Xreply_size ", REPLY_SIZE)); .mapiRead(con) - .mapiWrite(con, "Xauto_commit 1"); .mapiRead(con) + if (language == "sql") { + .mapiWrite(con, paste0("Xreply_size ", REPLY_SIZE)); .mapiRead(con) + .mapiWrite(con, "Xauto_commit 1"); .mapiRead(con) + } } } diff --git a/clients/R/MonetDB.R/src/mapisplit.c b/clients/R/MonetDB.R/src/mapisplit.c --- a/clients/R/MonetDB.R/src/mapisplit.c +++ b/clients/R/MonetDB.R/src/mapisplit.c @@ -1,36 +1,74 @@ -/* - * The contents of this file are subject to the MonetDB Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.monetdb.org/Legal/MonetDBLicense - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * The Original Code is the MonetDB Database System. - * - * The Initial Developer of the Original Code is CWI. - * Portions created by CWI are Copyright (C) 1997-July 2008 CWI. - * Copyright August 2008-2015 MonetDB B.V. - * All Rights Reserved. - */ - -#include <R.h> -#include <Rdefines.h> #include <assert.h> #include <string.h> #include <errno.h> +#include <R.h> +#include <Rdefines.h> + typedef enum { INQUOTES, ESCAPED, INTOKEN, INCRAP -} chrstate; +} mapi_line_chrstate; + +void mapi_line_split(char* line, char** out, size_t ncols) { + int cCol = 0; + int tokenStart = 2; + int endQuote = 0; + int curPos; + + int linelen = strlen(line); + mapi_line_chrstate state = INCRAP; + + for (curPos = 2; curPos < linelen - 1; curPos++) { + char chr = line[curPos]; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list