~hrbrmstr/sergeant-caffeinated

22ce18033163abda020c1704bfab42acd4eab5d3 — hrbrmstr 4 months ago 135af6c
{dbplyr} 2.0.0
M .Rbuildignore => .Rbuildignore +1 -0
@@ 11,3 11,4 @@
^apache-drill-1\.10\.0\.tar\.gz$
^cdh4-repository_1\.0_all\.deb$
^cran-comments\.md$
^java$

M DESCRIPTION => DESCRIPTION +17 -19
@@ 1,34 1,32 @@
Package: sergeant.caffeinated
Title: Tools to Transform and Query Data with 'Apache' 'Drill' ('JDBC')
Version: 0.2.1
Title: RJDBC Interface for Apache Drill
Version: 0.3.0
Authors@R: c(
      person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"), 
             comment = c(ORCID = "0000-0001-5670-2640"))
    )
Description: 'Apache Drill' is a low-latency distributed query engine designed to enable 
    data exploration and 'analytics' on both relational and non-relational 'datastores', 
    scaling to petabytes of data. Methods are provided that enable working with 'Apache' 
    'Drill' instances via the 'JDBC' 'DBI' and 'dplyr'/'dbplyr' idioms.
Depends:
    R (>= 3.1.2)
Description: Apache Drill is a low-latency distributed query engine designed to enable 
    data exploration and analytics on both relational and non-relational datastores, 
    scaling to petabytes of data. An RDBC interface with a thin set of 'dbplyr` 
    helper functions is provided.
URL: https://github.com/hrbrmstr/sergeant-caffeinated
BugReports: https://github.com/hrbrmstr/sergeant-caffeinated/issues
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Depends: 
    R (>= 3.6.0),
    rJava,
    RJDBC,
    DBI,
    dplyr,
    dbplyr (>= 2.0.0)
Imports: 
    DBI (>= 0.7),
    dplyr (>= 0.7.0),
    dbplyr (>= 1.1.0),
    htmltools (>= 0.3.6),
    scales (>= 0.4.1),
    RJDBC (>= 0.2-5),
    utils,
    methods,
    magrittr,
    bit64
Suggests:
    rJava (>= 0.9-8),
    testthat (>= 1.0.2),
    covr (>= 3.0.0)
RoxygenNote: 7.0.2
Suggests: 
    covr (>= 3.0.0), 
    tinytest
RoxygenNote: 7.1.1

M NAMESPACE => NAMESPACE +22 -42
@@ 1,57 1,37 @@
# Generated by roxygen2: do not edit by hand

S3method(db_data_type,DrillJDBCConnection)
S3method(db_data_type,tbl_drill_jdbc)
S3method(sql_escape_ident,DrillJDBCConnection)
S3method(dbplyr_edition,myConnectionClass)
S3method(sql_translate_env,DrillJDBCConnection)
S3method(src_tbls,src_dbi)
S3method(tbl,src_drill_jdbc)
export("%>%")
export(DrillJDBC)
export(drill_jdbc)
export(src_drill_jdbc)
export(tbl)
export(be_quiet)
exportClasses(DrillJDBCConnection)
exportClasses(DrillJDBCDriver)
exportClasses(DrillJDBCResult)
exportMethods(dbConnect)
exportMethods(dbDataType)
exportMethods(dbGetRowsAffected)
exportMethods(dbQuoteIdentifier)
exportMethods(dbSendQuery)
import(DBI)
import(bit64)
import(methods)
import(utils)
import(dbplyr)
importClassesFrom(RJDBC,JDBCConnection)
importClassesFrom(RJDBC,JDBCDriver)
importClassesFrom(RJDBC,JDBCResult)
importFrom(dbplyr,base_agg)
importFrom(dbplyr,base_scalar)
importFrom(dbplyr,base_win)
importFrom(dbplyr,build_sql)
importFrom(dbplyr,sql)
importFrom(dbplyr,sql_prefix)
importFrom(dbplyr,sql_quote)
importFrom(dbplyr,src_sql)
importFrom(dbplyr,tbl_sql)
importFrom(dbplyr,win_current_group)
importFrom(dbplyr,win_over)
importFrom(dbplyr,win_recycled)
importFrom(dplyr,"%>%")
importFrom(dplyr,bind_cols)
importFrom(dplyr,bind_rows)
importFrom(dplyr,copy_to)
importFrom(dplyr,data_frame)
importFrom(dplyr,db_data_type)
importFrom(dplyr,db_desc)
importFrom(dplyr,db_explain)
importFrom(dplyr,db_query_fields)
importFrom(dplyr,filter)
importFrom(dplyr,left_join)
importFrom(dplyr,mutate)
importFrom(dplyr,select)
importFrom(dplyr,sql_escape_ident)
importFrom(dplyr,sql_translate_env)
importFrom(dplyr,src)
importFrom(dplyr,src_tbls)
importFrom(dplyr,tbl)
importFrom(scales,comma)
importFrom(methods,callNextMethod)
importFrom(methods,initialize)
importFrom(methods,new)
importFrom(methods,setClass)
importFrom(methods,setGeneric)
importFrom(methods,setMethod)
importFrom(methods,show)
importFrom(rJava,.jaddClassPath)
importFrom(rJava,.jcheck)
importFrom(rJava,.jfindClass)
importFrom(rJava,.jinit)
importFrom(rJava,.jnew)
importFrom(rJava,.jnull)
importFrom(rJava,.jpackage)
importFrom(rJava,J)
importFrom(rJava,is.jnull)
importFrom(utils,globalVariables)

M R/aaa.r => R/aaa.r +10 -10
@@ 1,11 1,11 @@
utils::globalVariables(c("error", "everything", "isDirectory", "name", "params",
                         "permissions", "query", "error_msg"))

make_server <- function(drill_con) {

  sprintf("%s://%s:%s",
          ifelse(drill_con$ssl[1], "https", "http"),
          drill_con$host, drill_con$port)

}
# utils::globalVariables(c("error", "everything", "isDirectory", "name", "params",
#                          "permissions", "query", "error_msg"))
#
# make_server <- function(drill_con) {
#
#   sprintf("%s://%s:%s",
#           ifelse(drill_con$ssl[1], "https", "http"),
#           drill_con$host, drill_con$port)
#
# }
# #

D R/jdbc.r => R/jdbc.r +0 -426
@@ 1,426 0,0 @@
.fillStatementParameters <- function(s, l) {
  for (i in 1:length(l)) {
    v <- l[[i]]
    if (is.na(v)) { # map NAs to NULLs (courtesy of Axel Klenk)
      sqlType <- if (is.integer(v)) 4 else if (is.numeric(v)) 8 else 12
      rJava::.jcall(s, "V", "setNull", i, as.integer(sqlType))
    } else if (is.integer(v))
      rJava::.jcall(s, "V", "setInt", i, v[1])
    else if (is.numeric(v))
      rJava::.jcall(s, "V", "setDouble", i, as.double(v)[1])
    else
      rJava::.jcall(s, "V", "setString", i, as.character(v)[1])
  }
}

#' JDBC Driver for Drill database.
#'
#' @keywords internal
#' @export
setClass(
  Class = "DrillJDBCDriver",
  contains = "JDBCDriver"
)

#' Drill JDBC connection class.
#'
#' @export
#' @keywords internal
#' @export
setClass(
  Class = "DrillJDBCConnection",
  contains = "JDBCConnection"
)

#' Connect to Drill JDBC with your own connection string
#'
#' You should really use [drill_jdbc()] as it handles some cruft for
#' you, but you can specify the full JDBC connection string
#'
#' @md
#' @family Drill JDBC API
#' @param drv what you get back from [DrillJDBC()]
#' @param url your Drill connection strinfg
#' @param user,password username & password (leave as-is for no-auth)
#' @param ... additional `name=val` properties which will be set with Java's
#'        `SetProperty` method.
#' @export
setMethod(
  f = "dbConnect",
  signature = "DrillJDBCDriver",
  definition = function(drv, url, user='', password='', ...) {

    rJava::.jcall(
      "java/sql/DriverManager",
      "Ljava/sql/Connection;",
      "getConnection",
      as.character(url)[1],
      as.character(user)[1],
      as.character(password)[1],
      check = FALSE
    ) -> jc

    if (rJava::is.jnull(jc) && !rJava::is.jnull(drv@jdrv)) {
      # ok one reason for this to fail is its interaction with rJava's
      # class loader. In that case we try to load the driver directly.
      oex <- rJava::.jgetEx(TRUE)

      p <- rJava::.jnew("java/util/Properties")

      if (length(user)==1 && nchar(user)) {
        rJava::.jcall(p,"Ljava/lang/Object;","setProperty","user",user)
      }

      if (length(password)==1 && nchar(password)) {
        rJava::.jcall(p,"Ljava/lang/Object;","setProperty","password",password)
      }

      l <- list(...)
      if (length(names(l))) for (n in names(l)) {
        rJava::.jcall(p, "Ljava/lang/Object;", "setProperty", n, as.character(l[[n]]))
      }

      jc <- rJava::.jcall(drv@jdrv, "Ljava/sql/Connection;", "connect", as.character(url)[1], p)

    }

    .verify.JDBC.result(jc, "Unable to connect JDBC to ",url, , conn=NULL)

    new("DrillJDBCConnection", jc=jc, identifier.quote=drv@identifier.quote)

  },

  valueClass = "DrillJDBCConnection"

)

#' Drill JDBC dbDataType
#'
#' @param dbObj A \code{\linkS4class{DrillJDBCDriver}} object
#' @param obj Any R object
#' @param ... Extra optional parameters
#' @family Drill JDBC API
#' @export
setMethod(
  "dbDataType",
  "DrillJDBCConnection",
  function(dbObj, obj, ...) {
    if (is.integer(obj)) "INTEGER"
    else if (inherits(obj, "Date")) "DATE"
    else if (identical(class(obj), "times")) "TIME"
    else if (inherits(obj, "POSIXct")) "TIMESTAMP"
    else if (is.numeric(obj)) "DOUBLE"
    else "VARCHAR(255)"
  },
  valueClass = "character"
)


#' Drill's JDBC driver main class loader
#'
#' @family Drill JDBC API
#' @export
DrillJDBC <- function() {

  driverClass <-  "org.apache.drill.jdbc.Driver"

  ## expand all paths in the classPath
  classPath <- path.expand(unlist(strsplit(Sys.getenv("DRILL_JDBC_JAR"), .Platform$path.sep)))

  ## this is benign in that it's equivalent to rJava::.jaddClassPath if a JVM is running
  rJava::.jinit(classPath)

  rJava::.jaddClassPath(system.file("java", "RJDBC.jar", package="RJDBC"))
  rJava::.jaddClassPath(system.file("java", "slf4j-nop-1.7.25.jar", package = "sergeant.caffeinated"))

  if (nchar(driverClass) && rJava::is.jnull(rJava::.jfindClass(as.character(driverClass)[1]))) {
    stop("Cannot find JDBC driver class ",driverClass)
  }

  jdrv <- rJava::.jnew(driverClass, check=FALSE)

  rJava::.jcheck(TRUE)

  if (rJava::is.jnull(jdrv)) jdrv <- rJava::.jnull()

  new("DrillJDBCDriver", identifier.quote = "`", jdrv = jdrv)

}

#' Connect to Drill using JDBC
#'
#' The DRILL JDBC driver fully-qualified path must be placed in the
#' \code{DRILL_JDBC_JAR} environment variable. This is best done via \code{~/.Renviron}
#' for interactive work. e.g. \code{DRILL_JDBC_JAR=/usr/local/drill/jars/jdbc-driver/drill-jdbc-all-1.10.0.jar}
#'
#' [src_drill_jdbc()] wraps the JDBC [dbConnect()] connection instantation in
#' [dbplyr::src_dbi()] to return the equivalent of the REST driver's [src_drill()].
#'
#' @param nodes character vector of nodes. If more than one node, you can either have
#'              a single string with the comma-separated node:port pairs pre-made or
#'              pass in a character vector with multiple node:port strings and the
#'              function will make a comma-separated node string for you.
#' @param cluster_id the cluster id from \code{drill-override.conf}
#' @param schema an optional schema name to append to the JDBC connection string
#' @param use_zk are you connecting to a ZooKeeper instance (default: \code{TRUE}) or
#'               connecting to an individual DrillBit.
#' @family Drill JDBC API
#' @return a JDBC connection object
#' @references \url{https://drill.apache.org/docs/using-the-jdbc-driver/#using-the-jdbc-url-for-a-random-drillbit-connection}
#' @export
#' @examples \dontrun{
#' con <- drill_jdbc("localhost:2181", "main")
#' drill_query(con, "SELECT * FROM cp.`employee.json`")
#'
#' # you can also use the connection with RJDBC calls:
#' dbGetQuery(con, "SELECT * FROM cp.`employee.json`")
#'
#' # for local/embedded mode with default configuration info
#' con <- drill_jdbc("localhost:31010", use_zk=FALSE)
#' }
drill_jdbc <- function(nodes = "localhost:2181", cluster_id = NULL,
                       schema = NULL, use_zk = TRUE) {

  try_require("rJava")
  try_require("RJDBC")

  jar_path <- Sys.getenv("DRILL_JDBC_JAR")
  if (!file.exists(jar_path)) {
    stop(sprintf("Cannot locate DRILL JDBC JAR [%s]", jar_path))
  }

  drill_jdbc_drv <- DrillJDBC()

  conn_type <- "drillbit"
  if (use_zk) conn_type <- "zk"

  if (length(nodes) > 1) nodes <- paste0(nodes, collapse=",")

  conn_str <- sprintf("jdbc:drill:%s=%s", conn_type, nodes)

  if (!is.null(cluster_id)) {
    conn_str <- sprintf("%s%s", conn_str, sprintf("/drill/%s", cluster_id))
  }

  if (!is.null(schema)) conn_str <- sprintf("%s;%s", schema)

  message(sprintf("Using [%s]...", conn_str))

  dbConnect(drill_jdbc_drv, conn_str)

}

#' @rdname drill_jdbc
#' @family Drill JDBC API
#' @export
src_drill_jdbc <- function(nodes = "localhost:2181", cluster_id = NULL,
                           schema = NULL, use_zk = TRUE) {

  con <- drill_jdbc(nodes, cluster_id, schema, use_zk)
  src_sql("drill_jdbc", con)

}

#' @rdname drill_jdbc
#' @param src A Drill "src" created with \code{src_drill()}
#' @param from A Drill view or table specification
#' @param ... Extra parameters
#' @family Drill JDBC API
#' @export
tbl.src_drill_jdbc <- function(src, from, ...) {
  tbl_sql("drill_jdbc", src=src, from=from, ...)
}

#' Drill internals
#'
#' @rdname drill_jdbc_internals
#' @keywords internal
#' @export
db_data_type.DrillJDBCConnection <- function(con, fields, ...) {
  data_type <- function(x) {
    switch(
      class(x)[1],
      integer64 = "BIGINT",
      logical = "BOOLEAN",
      integer = "INTEGER",
      numeric = "DOUBLE",
      factor =  "CHARACTER",
      character = "CHARACTER",
      Date = "DATE",
      POSIXct = "TIMESTAMP",
      stop("Can't map type ", paste(class(x), collapse = "/"),
           " to a supported database type.")
    )
  }
  vapply(fields, data_type, character(1))
}

#' Drill internals
#'
#' @rdname drill_jdbc_internals
#' @keywords internal
#' @export
db_data_type.tbl_drill_jdbc <- db_data_type.DrillJDBCConnection

#' @rdname drill_jdbc_internals
#' @keywords internal
#' @export
setClass("DrillJDBCResult", representation("JDBCResult", jr="jobjRef", md="jobjRef", stat="jobjRef", pull="jobjRef"))

#' @rdname drill_jdbc_internals
#' @keywords internal
#' @export
setMethod(
  f = "dbSendQuery",
  signature = signature(conn="DrillJDBCConnection", statement="character"),
  definition = function(conn, statement, ..., list=NULL) {
    statement <- as.character(statement)[1L]
    ## if the statement starts with {call or {?= call then we use CallableStatement
    if (isTRUE(as.logical(grepl("^\\{(call|\\?= *call)", statement)))) {
      s <- rJava::.jcall(conn@jc, "Ljava/sql/CallableStatement;", "prepareCall", statement, check=FALSE)
      .verify.JDBC.result(s, "Unable to execute JDBC callable statement ",statement, conn=conn)
      if (length(list(...))) .fillStatementParameters(s, list(...))
      if (!is.null(list)) .fillStatementParameters(s, list)
      r <- rJava::.jcall(s, "Ljava/sql/ResultSet;", "executeQuery", check=FALSE)
      .verify.JDBC.result(r, "Unable to retrieve JDBC result set for ",statement, conn=conn)
    } else if (length(list(...)) || length(list)) { ## use prepared statements if there are additional arguments
      s <- rJava::.jcall(conn@jc, "Ljava/sql/PreparedStatement;", "prepareStatement", statement, check=FALSE)
      .verify.JDBC.result(s, "Unable to execute JDBC prepared statement ", statement, conn=conn)
      if (length(list(...))) .fillStatementParameters(s, list(...))
      if (!is.null(list)) .fillStatementParameters(s, list)
      r <- rJava::.jcall(s, "Ljava/sql/ResultSet;", "executeQuery", check=FALSE)
      .verify.JDBC.result(r, "Unable to retrieve JDBC result set for ",statement, conn=conn)
    } else { ## otherwise use a simple statement some DBs fail with the above)
      s <- rJava::.jcall(conn@jc, "Ljava/sql/Statement;", "createStatement")
      .verify.JDBC.result(s, "Unable to create simple JDBC statement ",statement, conn=conn)
      r <- rJava::.jcall(s, "Ljava/sql/ResultSet;", "executeQuery", as.character(statement)[1], check=FALSE)
      .verify.JDBC.result(r, "Unable to retrieve JDBC result set for ",statement, conn=conn)
    }
    md <- rJava::.jcall(r, "Ljava/sql/ResultSetMetaData;", "getMetaData", check=FALSE)
    .verify.JDBC.result(md, "Unable to retrieve JDBC result set meta data for ",statement, " in dbSendQuery")
    new("DrillJDBCResult", jr=r, md=md, stat=s, pull=rJava::.jnull())
  })

#' @rdname drill_jdbc_internals
#' @keywords internal
#' @export
sql_escape_ident.DrillJDBCConnection <- function(con, x) {
  ifelse(grepl(con@identifier.quote, x), sql_quote(x, ' '), sql_quote(x, con@identifier.quote))
}

#' @rdname drill_jdbc_internals
#' @keywords internal
#' @export
sql_translate_env.DrillJDBCConnection <- function(con) {

  x <- con

  dbplyr::sql_variant(

    scalar = dbplyr::sql_translator(
      .parent = dbplyr::base_scalar,
      `!=` = dbplyr::sql_infix("<>"),
      as.numeric = function(x) build_sql("CAST(", x, " AS DOUBLE)"),
      as.character = function(x) build_sql("CAST(", x, " AS CHARACTER)"),
      as.date = function(x) build_sql("CAST(", x, " AS DATE)"),
      as.posixct = function(x) build_sql("CAST(", x, " AS TIMESTAMP)"),
      as.logical = function(x) build_sql("CAST(", x, " AS BOOLEAN)"),
      date_part = function(x, y) build_sql("DATE_PART(", x, ",", y ,")"),
      grepl = function(x, y) build_sql("CONTAINS(", y, ", ", x, ")"),
      gsub = function(x, y, z) build_sql("REGEXP_REPLACE(", z, ", ", x, ",", y ,")"),
      str_replace = function(x, y, z) build_sql("REGEXP_REPLACE(", x, ", ", y, ",", z ,")"),
      trimws = function(x) build_sql("TRIM(both ' ' FROM ", x, ")"),
      cbrt = sql_prefix("CBRT", 1),
      degrees = sql_prefix("DEGREES", 1),
      e = sql_prefix("E", 0),
      row_number = sql_prefix("row_number", 0),
      lshift = sql_prefix("LSHIFT", 2),
      mod = sql_prefix("MOD", 2),
      age = sql_prefix("AGE", 1),
      negative = sql_prefix("NEGATIVE", 1),
      pi = sql_prefix("PI", 0),
      pow = sql_prefix("POW", 2),
      radians = sql_prefix("RADIANS", 1),
      rand = sql_prefix("RAND", 0),
      rshift = sql_prefix("RSHIFT", 2),
      trunc = sql_prefix("TRUNC", 2),
      contains = sql_prefix("CONTAINS", 2),
      convert_to = sql_prefix("CONVERT_TO", 2),
      convert_from = sql_prefix("CONVERT_FROM", 2),
      string_binary = sql_prefix("STRING_BINARY", 1),
      binary_string = sql_prefix("BINARY_STRING", 1),
      to_char = sql_prefix("TO_CHAR", 2),
      to_date = sql_prefix("TO_DATE", 2),
      to_number = sql_prefix("TO_NUMBER", 2),
      char_to_timestamp = sql_prefix("TO_TIMESTAMP", 2),
      double_to_timestamp = sql_prefix("TO_TIMESTAMP", 1),
      char_length = sql_prefix("CHAR_LENGTH", 1),
      flatten = sql_prefix("FLATTEN", 1),
      kvgen = sql_prefix("KVGEN", 1),
      repeated_count = sql_prefix("REPEATED_COUNT", 1),
      repeated_contains = sql_prefix("REPEATED_CONTAINS", 2),
      ilike = sql_prefix("ILIKE", 2),
      init_cap = sql_prefix("INIT_CAP", 1),
      length = sql_prefix("LENGTH", 1),
      lower = sql_prefix("LOWER", 1),
      str_to_lower = sql_prefix("LOWER", 1),
      tolower = sql_prefix("LOWER", 1),
      ltrim = sql_prefix("LTRIM", 2),
      nullif = sql_prefix("NULLIF", 2),
      position = function(x, y) build_sql("POSITION(", x, " IN ", y, ")"),
      regexp_replace = sql_prefix("REGEXP_REPLACE", 3),
      rtrim = sql_prefix("RTRIM", 2),
      rpad = sql_prefix("RPAD", 2),
      rpad_with = sql_prefix("RPAD", 3),
      lpad = sql_prefix("LPAD", 2),
      lpad_with = sql_prefix("LPAD", 3),
      strpos = sql_prefix("STRPOS", 2),
      substr = sql_prefix("SUBSTR", 3),
      str_sub = sql_prefix("SUBSTR", 3),
      trim = function(x, y, z) build_sql("TRIM(", x, " ", y, " FROM ", z, ")"),
      upper = sql_prefix("UPPER", 1),
      str_to_upper = sql_prefix("UPPER", 1),
      toupper = sql_prefix("UPPER", 1)
    ),

    aggregate = dbplyr::sql_translator(
      .parent = dbplyr::base_agg,
      n = function() dbplyr::sql("COUNT(*)"),
      cor = dbplyr::sql_prefix("CORR"),
      cov = dbplyr::sql_prefix("COVAR_SAMP"),
      sd =  dbplyr::sql_prefix("STDDEV_SAMP"),
      var = dbplyr::sql_prefix("VAR_SAMP"),
      n_distinct = function(x) {
        dbplyr::build_sql(dbplyr::sql("COUNT(DISTINCT "), x, dbplyr::sql(")"))
      }
    ),

    window = dbplyr::sql_translator(
      .parent = dbplyr::base_win,
      n = function() { dbplyr::win_over(dbplyr::sql("count(*)"),
                                        partition = dbplyr::win_current_group()) },
      cor = dbplyr::win_recycled("corr"),
      cov = dbplyr::win_recycled("covar_samp"),
      sd =  dbplyr::win_recycled("stddev_samp"),
      var = dbplyr::win_recycled("var_samp"),
      all = dbplyr::win_recycled("bool_and"),
      any = dbplyr::win_recycled("bool_or")
    )

  )

}

#' src tbls
#'
#' "SHOW DATABASES"
#'
#' @rdname drill_jdbc_internals
#' @family Drill JDBC API
#' @keywords internal
#' @param x x
#' @export
src_tbls.src_dbi <- function(x) {
  tmp <- dbGetQuery(x$con, "SHOW DATABASES")
  paste0(unlist(tmp$SCHEMA_NAME, use.names=FALSE), collapse=", ")
}

A R/new-jdbc.R => R/new-jdbc.R +233 -0
@@ 0,0 1,233 @@
#' Silence Java reflection warnings
#'
#' @export
be_quiet <- function() {
  rJava::J("is.rud.sergeant_caffeinated.App")$beQuiet()
}

#' @keywords internal
#' @export
dbplyr_edition.myConnectionClass <- function(con) 2L

#' @rdname DrillJDBC
#' @keywords internal
#' @export
setClass("DrillJDBCDriver", contains = "JDBCDriver")

#' Create a Drill JDBC connection
#'
#' @param identifier.quote quote
#' @param drill_jdbc_jar_path  path
#' @keywords internal
#' @export
DrillJDBC <- function(identifier.quote = "`", drill_jdbc_jar_path = Sys.getenv("DRILL_JDBC_JAR")) {

  driverClass <-  "org.apache.drill.jdbc.Driver"

  ## expand all paths in the classPath
  classPath <- path.expand(unlist(strsplit(drill_jdbc_jar_path, .Platform$path.sep)))

  ## this is benign in that it's equivalent to rJava::.jaddClassPath if a JVM is running
  rJava::.jinit(classPath)

  if (nchar(driverClass) && rJava::is.jnull(rJava::.jfindClass(as.character(driverClass)[1]))) {
    stop("Cannot find JDBC driver class ",driverClass)
  }

  jdrv <- rJava::.jnew(driverClass, check=FALSE)

  rJava::.jcheck(TRUE)

  if (rJava::is.jnull(jdrv)) jdrv <- rJava::.jnull()

  new("DrillJDBCDriver", identifier.quote = identifier.quote)

}

#' @rdname DrillJDBC
#' @keywords internal
#' @export
setClass("DrillJDBCConnection", contains = "JDBCConnection")

#' Connect to a schema/table
#'
#' @param drv driver
#' @param url connection string
#' @param user,password creds
#' @param ... extra params
#' @aliases dbConnect
#' @export
setMethod(
  f = "dbConnect",
  signature = "DrillJDBCDriver",
  definition = function(drv, url, user='', password='', ...) {
    res <- callNextMethod(drv, url, user, password, ...)
    cls <- "DrillJDBCConnection"
    attr(cls, "package") <- "sergeant.caffeinated"
    class(res) <- cls
    return(res)
  }
)

quote_identifier <- function(conn, x, ...) {
  ifelse(grepl("`", x), dbplyr::sql_quote(x, ' '), dbplyr::sql_quote(x, '`'))
}

#' Thin wrapper for dbQuoteIdentifier
#'
#' @param conn connection
#' @param x, item to quote
#' @param ... passed on to downstream methods
#' @aliases dbQuoteIdentifier
#' @export
setMethod(
  "dbQuoteIdentifier",
  signature("DrillJDBCConnection", "character"),
  quote_identifier
)

#' @rdname DrillJDBC
#' @keywords internal
#' @export
setClass("DrillJDBCResult", contains = "JDBCResult")

#' Drill JDBC dbGetRowsAffected
#'
#' @param res A \code{\linkS4class{DrillJDBCResult}} object
#' @param ... Extra optional parameters
#' @aliases dbGetRowsAffected
#' @export
setMethod(
  f = "dbGetRowsAffected",
  signature = "DrillJDBCResult",
  definition = function(res, ...) {
    nr <- 0
    while(res@jr$`next`()) nr <- nr+1
    return(nr)
  }
)

#' Thin wrapper for dbSendQuery
#'
#' @param conn connection
#' @param statement SQL statement,
#' @param ... passed on
#' @param list list
#' @aliases dbSendQuery
#' @export
setMethod(
  f = "dbSendQuery",
  signature = signature(conn="DrillJDBCConnection", statement="character"),
  definition = function(conn, statement, ..., list=NULL) {
    res <- callNextMethod(conn, statement, ..., list=list)
    cls <- "DrillJDBCResult"
    attr(cls, "package") <- "sergeant.caffeinated"
    class(res) <- cls
    res
  }
)

#' Thin wrapper for sql_translate_env
#'
#' @param con connection
#' @keywords internal
#' @export
sql_translate_env.DrillJDBCConnection <- function(con) {

  x <- con

  dbplyr::sql_variant(

    scalar = dbplyr::sql_translator(
      .parent = dbplyr::base_scalar,
      `!=` = dbplyr::sql_infix("<>"),
      as.numeric = function(x) build_sql("CAST(", x, " AS DOUBLE)"),
      as.character = function(x) build_sql("CAST(", x, " AS CHARACTER)"),
      as.date = function(x) build_sql("CAST(", x, " AS DATE)"),
      as.posixct = function(x) build_sql("CAST(", x, " AS TIMESTAMP)"),
      as.logical = function(x) build_sql("CAST(", x, " AS BOOLEAN)"),
      date_part = function(x, y) build_sql("DATE_PART(", x, ",", y ,")"),
      grepl = function(x, y) build_sql("CONTAINS(", y, ", ", x, ")"),
      gsub = function(x, y, z) build_sql("REGEXP_REPLACE(", z, ", ", x, ",", y ,")"),
      str_replace = function(x, y, z) build_sql("REGEXP_REPLACE(", x, ", ", y, ",", z ,")"),
      trimws = function(x) build_sql("TRIM(both ' ' FROM ", x, ")"),
      cbrt = sql_prefix("CBRT", 1),
      degrees = sql_prefix("DEGREES", 1),
      e = sql_prefix("E", 0),
      row_number = sql_prefix("row_number", 0),
      lshift = sql_prefix("LSHIFT", 2),
      mod = sql_prefix("MOD", 2),
      age = sql_prefix("AGE", 1),
      negative = sql_prefix("NEGATIVE", 1),
      pi = sql_prefix("PI", 0),
      pow = sql_prefix("POW", 2),
      radians = sql_prefix("RADIANS", 1),
      rand = sql_prefix("RAND", 0),
      rshift = sql_prefix("RSHIFT", 2),
      trunc = sql_prefix("TRUNC", 2),
      contains = sql_prefix("CONTAINS", 2),
      convert_to = sql_prefix("CONVERT_TO", 2),
      convert_from = sql_prefix("CONVERT_FROM", 2),
      string_binary = sql_prefix("STRING_BINARY", 1),
      binary_string = sql_prefix("BINARY_STRING", 1),
      to_char = sql_prefix("TO_CHAR", 2),
      to_date = sql_prefix("TO_DATE", 2),
      to_number = sql_prefix("TO_NUMBER", 2),
      char_to_timestamp = sql_prefix("TO_TIMESTAMP", 2),
      double_to_timestamp = sql_prefix("TO_TIMESTAMP", 1),
      char_length = sql_prefix("CHAR_LENGTH", 1),
      flatten = sql_prefix("FLATTEN", 1),
      kvgen = sql_prefix("KVGEN", 1),
      repeated_count = sql_prefix("REPEATED_COUNT", 1),
      repeated_contains = sql_prefix("REPEATED_CONTAINS", 2),
      ilike = sql_prefix("ILIKE", 2),
      init_cap = sql_prefix("INIT_CAP", 1),
      length = sql_prefix("LENGTH", 1),
      lower = sql_prefix("LOWER", 1),
      str_to_lower = sql_prefix("LOWER", 1),
      tolower = sql_prefix("LOWER", 1),
      ltrim = sql_prefix("LTRIM", 2),
      nullif = sql_prefix("NULLIF", 2),
      position = function(x, y) build_sql("POSITION(", x, " IN ", y, ")"),
      regexp_replace = sql_prefix("REGEXP_REPLACE", 3),
      rtrim = sql_prefix("RTRIM", 2),
      rpad = sql_prefix("RPAD", 2),
      rpad_with = sql_prefix("RPAD", 3),
      lpad = sql_prefix("LPAD", 2),
      lpad_with = sql_prefix("LPAD", 3),
      strpos = sql_prefix("STRPOS", 2),
      substr = sql_prefix("SUBSTR", 3),
      str_sub = sql_prefix("SUBSTR", 3),
      trim = function(x, y, z) build_sql("TRIM(", x, " ", y, " FROM ", z, ")"),
      upper = sql_prefix("UPPER", 1),
      str_to_upper = sql_prefix("UPPER", 1),
      toupper = sql_prefix("UPPER", 1)
    ),

    aggregate = dbplyr::sql_translator(
      .parent = dbplyr::base_agg,
      n = function() dbplyr::sql("COUNT(*)"),
      cor = dbplyr::sql_prefix("CORR"),
      cov = dbplyr::sql_prefix("COVAR_SAMP"),
      sd =  dbplyr::sql_prefix("STDDEV_SAMP"),
      var = dbplyr::sql_prefix("VAR_SAMP"),
      n_distinct = function(x) {
        dbplyr::build_sql(dbplyr::sql("COUNT(DISTINCT "), x, dbplyr::sql(")"))
      }
    ),

    window = dbplyr::sql_translator(
      .parent = dbplyr::base_win,
      n = function() { dbplyr::win_over(dbplyr::sql("count(*)"),
                                        partition = dbplyr::win_current_group()) },
      cor = dbplyr::win_recycled("corr"),
      cov = dbplyr::win_recycled("covar_samp"),
      sd =  dbplyr::win_recycled("stddev_samp"),
      var = dbplyr::win_recycled("var_samp"),
      all = dbplyr::win_recycled("bool_and"),
      any = dbplyr::win_recycled("bool_or")
    )

  )

}

M R/sergeant-caffeinated-package.R => R/sergeant-caffeinated-package.R +8 -17
@@ 17,30 17,26 @@
#' accepting requests from the client, processing the queries, and returning results to
#' the client.
#'
#' You can install and run a Drillbit service on one node or on many nodes to form a
#' distributed cluster environment. When a Drillbit runs on each data node in a cluster,
#' You can install and run a drillbit service on one node or on many nodes to form a
#' distributed cluster environment. When a drillbit runs on each data node in a cluster,
#' Drill can maximize data locality during query execution without moving data over the
#' network or between nodes. Drill uses ZooKeeper to maintain cluster membership and health
#' check information.
#'
#' Methods are provided to work with Drill via the native JDBC & REST APIs along with R
#' \code{DBI} and \code{dplyr} interfaces.
#' An RDBC interface with a thin set of 'dbplyr` helper functions is provided.
#'
#' @name sergeant.caffeinated
#' @references \href{https://drill.apache.org/docs/}{Drill documentation}
#' @docType package
#' @author Bob Rudis (bob@@rud.is)
#' @importFrom scales comma
#' @importFrom dplyr mutate select left_join bind_cols bind_rows data_frame tbl filter
#' @importFrom dplyr db_desc src db_data_type db_explain sql_translate_env copy_to %>%
#' @importFrom dplyr db_query_fields src_tbls sql_escape_ident
#' @importFrom dbplyr build_sql sql_prefix sql_quote src_sql tbl_sql
#' @importFrom dbplyr win_recycled win_current_group base_win base_agg base_scalar win_over sql
#' @import utils DBI methods bit64
#' @import dbplyr DBI
#' @importFrom rJava J .jinit .jnew is.jnull .jaddClassPath .jfindClass .jcheck .jnull .jpackage
#' @importFrom dplyr sql_translate_env
#' @importFrom utils globalVariables
#' @importFrom methods setClass setGeneric setMethod callNextMethod new initialize show
#' @importClassesFrom RJDBC JDBCDriver JDBCConnection JDBCResult
NULL


#' sergeant exported operators
#'
#' The following functions are imported and then re-exported


@@ 54,8 50,3 @@ NULL
#' @export
#' @rdname sergeant-caffeinated-exports
NULL

#' @name tbl
#' @export
#' @rdname sergeant-caffeinated-exports
NULL

D R/utils.r => R/utils.r +0 -62
@@ 1,62 0,0 @@
.verify.JDBC.result <- function(result, ..., conn=NULL) {

  if (rJava::is.jnull(result)) {

    x <- rJava::.jgetEx(TRUE)

    if (rJava::is.jnull(x)) {
      stop(...)
    } else if (is.null(conn)) {
      stop(...)
    } else {

      jr <- unlist(rJava::.jcall(x, "S", "getMessage"))

      resp <- unlist(list(...))

      jdbc_err <- resp[1]
      oq <- resp[2]

      resp <- unlist(strsplit(jr, "\n"))

      err <- resp[grepl("Error Id", resp)]

      resp <- resp[resp != ""]
      resp <- resp[!grepl("Error Id", resp)]

      err <- sub("^.*: ", "", err)
      err <- unlist(strsplit(err, "[[:space:]]+"))[1]

      oq <- unlist(strsplit(oq, "\n"))

      c(
        sprintf("%s:\n", jdbc_err),
        sprintf("%3d: %s", 1:length(oq), oq),
        " ",
        resp,
        sprintf(
          "\nQuery Profile Error Id: %s", err
        )
      ) -> resp

      resp <- paste0(resp, collapse="\n")

      stop(resp, call.=FALSE)

    }

  }

}


try_require <- function(package, fun) {
  if (requireNamespace(package, quietly = TRUE)) {
    library(package, character.only = TRUE)
    return(invisible())
  }

  stop("Package `", package, "` required for `", fun , "`.\n", # nocov start
       "Please install and try again.", call. = FALSE) # nocov end
}


M R/zzz.R => R/zzz.R +3 -1
@@ 1,3 1,5 @@
.onLoad <- function(libname, pkgname) {
  if (requireNamespace("rJava")) rJava::.jpackage(pkgname, lib.loc = libname)
  rJava::.jpackage(pkgname, lib.loc = libname)
  rJava::.jaddClassPath(system.file("java", "RJDBC.jar", package = "RJDBC"))
  rJava::J("java.util.logging.LogManager")$getLogManager()$reset()
}

A inst/java/sergeant-caffeinated-1.0-SNAPSHOT.jar => inst/java/sergeant-caffeinated-1.0-SNAPSHOT.jar +0 -0
A inst/java/slf4j-api-2.0.0-alpha1.jar => inst/java/slf4j-api-2.0.0-alpha1.jar +0 -0
A inst/tinytest/test_sergeant.caffeinated.R => inst/tinytest/test_sergeant.caffeinated.R +18 -0
@@ 0,0 1,18 @@
library(sergeant.caffeinated)

test_host <- Sys.getenv("DRILL_TEST_HOST", "localhost")

be_quiet()

db <- dbConnect(drv = DrillJDBC(), sprintf("jdbc:drill:zk=%s", test_host))

dbCanConnect(drv = DrillJDBC(), sprintf("jdbc:drill:zk=%s", test_host))

dbExecute(db, "ALTER SESSION SET planner.cpu_load_average = 0.8")

test_dplyr <- tbl(db, "cp.`employee.json`")

expect_equal(inherits(test_dplyr, "tbl"), TRUE)

expect_equal(inherits(dplyr::count(test_dplyr, gender), "tbl"), TRUE)


A java/sergeant-caffeinated/.gitignore => java/sergeant-caffeinated/.gitignore +2 -0
@@ 0,0 1,2 @@
deps
target

A java/sergeant-caffeinated/Makefile => java/sergeant-caffeinated/Makefile +14 -0
@@ 0,0 1,14 @@
.PHONY: clean pkg deps run init

pkg:
	mvn --quiet package
	cp target/sergeant-caffeinated-1.0-SNAPSHOT.jar ../../inst/java

clean:
	mvn clean

deps:
	mvn dependency:copy-dependencies -DoutputDirectory=deps

init:
	mvn archetype:generate -DgroupId=is.rud.sergeant-caffeinated -DartifactId=sergeant-caffeinated -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
\ No newline at end of file

A java/sergeant-caffeinated/pom.xml => java/sergeant-caffeinated/pom.xml +75 -0
@@ 0,0 1,75 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>is.rud.sergeant_caffeinated</groupId>
  <artifactId>sergeant-caffeinated</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>sergeant_caffeinated</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

A java/sergeant-caffeinated/src/main/java/is/rud/sergeant-caffeinated/App.java => java/sergeant-caffeinated/src/main/java/is/rud/sergeant-caffeinated/App.java +30 -0
@@ 0,0 1,30 @@
package is.rud.sergeant_caffeinated;

// https://stackoverflow.com/a/53517025

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class App  {

	@SuppressWarnings("unchecked")
	public static void beQuiet() {

		try {
			Class unsafeClass = Class.forName("sun.misc.Unsafe");
			Field field = unsafeClass.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			Object unsafe = field.get(null);

			Method putObjectVolatile = unsafeClass.getDeclaredMethod("putObjectVolatile", Object.class, long.class, Object.class);
			Method staticFieldOffset = unsafeClass.getDeclaredMethod("staticFieldOffset", Field.class);

			Class loggerClass = Class.forName("jdk.internal.module.IllegalAccessLogger");
			Field loggerField = loggerClass.getDeclaredField("logger");
			Long offset = (Long) staticFieldOffset.invoke(unsafe, loggerField);
			putObjectVolatile.invoke(unsafe, loggerClass, offset, null);
		} catch (Exception ignored) {
		}

	}
}

A java/sergeant-caffeinated/src/test/java/is/rud/sergeant-caffeinated/AppTest.java => java/sergeant-caffeinated/src/test/java/is/rud/sergeant-caffeinated/AppTest.java +20 -0
@@ 0,0 1,20 @@
package is.rud.sergeant_caffeinated;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

/**
 * Unit test for simple App.
 */
public class AppTest 
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }
}

M man/DrillJDBC.Rd => man/DrillJDBC.Rd +18 -13
@@ 1,19 1,24 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
\name{DrillJDBC}
% Please edit documentation in R/new-jdbc.R
\docType{class}
\name{DrillJDBCDriver-class}
\alias{DrillJDBCDriver-class}
\alias{DrillJDBC}
\title{Drill's JDBC driver main class loader}
\alias{DrillJDBCConnection-class}
\alias{DrillJDBCResult-class}
\title{Create a Drill JDBC connection}
\usage{
DrillJDBC()
DrillJDBC(
  identifier.quote = "`",
  drill_jdbc_jar_path = Sys.getenv("DRILL_JDBC_JAR")
)
}
\description{
Drill's JDBC driver main class loader
\arguments{
\item{identifier.quote}{quote}

\item{drill_jdbc_jar_path}{path}
}
\seealso{
Other Drill JDBC API: 
\code{\link{dbConnect,DrillJDBCDriver-method}},
\code{\link{dbDataType,DrillJDBCConnection-method}},
\code{\link{db_data_type.DrillJDBCConnection}()},
\code{\link{drill_jdbc}()}
\description{
Create a Drill JDBC connection
}
\concept{Drill JDBC API}
\keyword{internal}

D man/DrillJDBCConnection-class.Rd => man/DrillJDBCConnection-class.Rd +0 -10
@@ 1,10 0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
\docType{class}
\name{DrillJDBCConnection-class}
\alias{DrillJDBCConnection-class}
\title{Drill JDBC connection class.}
\description{
Drill JDBC connection class.
}
\keyword{internal}

D man/DrillJDBCDriver-class.Rd => man/DrillJDBCDriver-class.Rd +0 -10
@@ 1,10 0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
\docType{class}
\name{DrillJDBCDriver-class}
\alias{DrillJDBCDriver-class}
\title{JDBC Driver for Drill database.}
\description{
JDBC Driver for Drill database.
}
\keyword{internal}

A man/be_quiet.Rd => man/be_quiet.Rd +11 -0
@@ 0,0 1,11 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/new-jdbc.R
\name{be_quiet}
\alias{be_quiet}
\title{Silence Java reflection warnings}
\usage{
be_quiet()
}
\description{
Silence Java reflection warnings
}

M man/dbConnect-DrillJDBCDriver-method.Rd => man/dbConnect-DrillJDBCDriver-method.Rd +8 -17
@@ 1,30 1,21 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
% Please edit documentation in R/new-jdbc.R
\name{dbConnect,DrillJDBCDriver-method}
\alias{dbConnect,DrillJDBCDriver-method}
\title{Connect to Drill JDBC with your own connection string}
\alias{dbConnect}
\title{Connect to a schema/table}
\usage{
\S4method{dbConnect}{DrillJDBCDriver}(drv, url, user = "", password = "", ...)
}
\arguments{
\item{drv}{what you get back from \code{\link[=DrillJDBC]{DrillJDBC()}}}
\item{drv}{driver}

\item{url}{your Drill connection strinfg}
\item{url}{connection string}

\item{user, password}{username & password (leave as-is for no-auth)}
\item{user, password}{creds}

\item{...}{additional \code{name=val} properties which will be set with Java's
\code{SetProperty} method.}
\item{...}{extra params}
}
\description{
You should really use \code{\link[=drill_jdbc]{drill_jdbc()}} as it handles some cruft for
you, but you can specify the full JDBC connection string
Connect to a schema/table
}
\seealso{
Other Drill JDBC API: 
\code{\link{DrillJDBC}()},
\code{\link{dbDataType,DrillJDBCConnection-method}},
\code{\link{db_data_type.DrillJDBCConnection}()},
\code{\link{drill_jdbc}()}
}
\concept{Drill JDBC API}

D man/dbDataType-DrillJDBCConnection-method.Rd => man/dbDataType-DrillJDBCConnection-method.Rd +0 -26
@@ 1,26 0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
\name{dbDataType,DrillJDBCConnection-method}
\alias{dbDataType,DrillJDBCConnection-method}
\title{Drill JDBC dbDataType}
\usage{
\S4method{dbDataType}{DrillJDBCConnection}(dbObj, obj, ...)
}
\arguments{
\item{dbObj}{A \code{\linkS4class{DrillJDBCDriver}} object}

\item{obj}{Any R object}

\item{...}{Extra optional parameters}
}
\description{
Drill JDBC dbDataType
}
\seealso{
Other Drill JDBC API: 
\code{\link{DrillJDBC}()},
\code{\link{dbConnect,DrillJDBCDriver-method}},
\code{\link{db_data_type.DrillJDBCConnection}()},
\code{\link{drill_jdbc}()}
}
\concept{Drill JDBC API}

A man/dbGetRowsAffected-DrillJDBCResult-method.Rd => man/dbGetRowsAffected-DrillJDBCResult-method.Rd +17 -0
@@ 0,0 1,17 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/new-jdbc.R
\name{dbGetRowsAffected,DrillJDBCResult-method}
\alias{dbGetRowsAffected,DrillJDBCResult-method}
\alias{dbGetRowsAffected}
\title{Drill JDBC dbGetRowsAffected}
\usage{
\S4method{dbGetRowsAffected}{DrillJDBCResult}(res, ...)
}
\arguments{
\item{res}{A \code{\linkS4class{DrillJDBCResult}} object}

\item{...}{Extra optional parameters}
}
\description{
Drill JDBC dbGetRowsAffected
}

A man/dbQuoteIdentifier-DrillJDBCConnection-character-method.Rd => man/dbQuoteIdentifier-DrillJDBCConnection-character-method.Rd +19 -0
@@ 0,0 1,19 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/new-jdbc.R
\name{dbQuoteIdentifier,DrillJDBCConnection,character-method}
\alias{dbQuoteIdentifier,DrillJDBCConnection,character-method}
\alias{dbQuoteIdentifier}
\title{Thin wrapper for dbQuoteIdentifier}
\usage{
\S4method{dbQuoteIdentifier}{DrillJDBCConnection,character}(conn, x, ...)
}
\arguments{
\item{conn}{connection}

\item{x, }{item to quote}

\item{...}{passed on to downstream methods}
}
\description{
Thin wrapper for dbQuoteIdentifier
}

A man/dbSendQuery-DrillJDBCConnection-character-method.Rd => man/dbSendQuery-DrillJDBCConnection-character-method.Rd +21 -0
@@ 0,0 1,21 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/new-jdbc.R
\name{dbSendQuery,DrillJDBCConnection,character-method}
\alias{dbSendQuery,DrillJDBCConnection,character-method}
\alias{dbSendQuery}
\title{Thin wrapper for dbSendQuery}
\usage{
\S4method{dbSendQuery}{DrillJDBCConnection,character}(conn, statement, ..., list = NULL)
}
\arguments{
\item{conn}{connection}

\item{statement}{SQL statement,}

\item{...}{passed on}

\item{list}{list}
}
\description{
Thin wrapper for dbSendQuery
}

D man/drill_jdbc.Rd => man/drill_jdbc.Rd +0 -90
@@ 1,90 0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
\name{drill_jdbc}
\alias{drill_jdbc}
\alias{src_drill_jdbc}
\alias{tbl.src_drill_jdbc}
\title{Connect to Drill using JDBC}
\usage{
drill_jdbc(
  nodes = "localhost:2181",
  cluster_id = NULL,
  schema = NULL,
  use_zk = TRUE
)

src_drill_jdbc(
  nodes = "localhost:2181",
  cluster_id = NULL,
  schema = NULL,
  use_zk = TRUE
)

\method{tbl}{src_drill_jdbc}(src, from, ...)
}
\arguments{
\item{nodes}{character vector of nodes. If more than one node, you can either have
a single string with the comma-separated node:port pairs pre-made or
pass in a character vector with multiple node:port strings and the
function will make a comma-separated node string for you.}

\item{cluster_id}{the cluster id from \code{drill-override.conf}}

\item{schema}{an optional schema name to append to the JDBC connection string}

\item{use_zk}{are you connecting to a ZooKeeper instance (default: \code{TRUE}) or
connecting to an individual DrillBit.}

\item{src}{A Drill "src" created with \code{src_drill()}}

\item{from}{A Drill view or table specification}

\item{...}{Extra parameters}
}
\value{
a JDBC connection object
}
\description{
The DRILL JDBC driver fully-qualified path must be placed in the
\code{DRILL_JDBC_JAR} environment variable. This is best done via \code{~/.Renviron}
for interactive work. e.g. \code{DRILL_JDBC_JAR=/usr/local/drill/jars/jdbc-driver/drill-jdbc-all-1.10.0.jar}
}
\details{
[src_drill_jdbc()] wraps the JDBC [dbConnect()] connection instantation in
[dbplyr::src_dbi()] to return the equivalent of the REST driver's [src_drill()].
}
\examples{
\dontrun{
con <- drill_jdbc("localhost:2181", "main")
drill_query(con, "SELECT * FROM cp.`employee.json`")

# you can also use the connection with RJDBC calls:
dbGetQuery(con, "SELECT * FROM cp.`employee.json`")

# for local/embedded mode with default configuration info
con <- drill_jdbc("localhost:31010", use_zk=FALSE)
}
}
\references{
\url{https://drill.apache.org/docs/using-the-jdbc-driver/#using-the-jdbc-url-for-a-random-drillbit-connection}
}
\seealso{
Other Drill JDBC API: 
\code{\link{DrillJDBC}()},
\code{\link{dbConnect,DrillJDBCDriver-method}},
\code{\link{dbDataType,DrillJDBCConnection-method}},
\code{\link{db_data_type.DrillJDBCConnection}()}

Other Drill JDBC API: 
\code{\link{DrillJDBC}()},
\code{\link{dbConnect,DrillJDBCDriver-method}},
\code{\link{dbDataType,DrillJDBCConnection-method}},
\code{\link{db_data_type.DrillJDBCConnection}()}

Other Drill JDBC API: 
\code{\link{DrillJDBC}()},
\code{\link{dbConnect,DrillJDBCDriver-method}},
\code{\link{dbDataType,DrillJDBCConnection-method}},
\code{\link{db_data_type.DrillJDBCConnection}()}
}
\concept{Drill JDBC API}

D man/drill_jdbc_internals.Rd => man/drill_jdbc_internals.Rd +0 -40
@@ 1,40 0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/jdbc.r
\docType{class}
\name{db_data_type.DrillJDBCConnection}
\alias{db_data_type.DrillJDBCConnection}
\alias{db_data_type.tbl_drill_jdbc}
\alias{DrillJDBCResult-class}
\alias{dbSendQuery,DrillJDBCConnection,character-method}
\alias{sql_escape_ident.DrillJDBCConnection}
\alias{sql_translate_env.DrillJDBCConnection}
\alias{src_tbls.src_dbi}
\title{Drill internals}
\usage{
\method{db_data_type}{DrillJDBCConnection}(con, fields, ...)

\method{db_data_type}{tbl_drill_jdbc}(con, fields, ...)

\S4method{dbSendQuery}{DrillJDBCConnection,character}(conn, statement, ..., list = NULL)

\method{sql_escape_ident}{DrillJDBCConnection}(con, x)

\method{sql_translate_env}{DrillJDBCConnection}(con)

\method{src_tbls}{src_dbi}(x)
}
\arguments{
\item{x}{x}
}
\description{
"SHOW DATABASES"
}
\seealso{
Other Drill JDBC API: 
\code{\link{DrillJDBC}()},
\code{\link{dbConnect,DrillJDBCDriver-method}},
\code{\link{dbDataType,DrillJDBCConnection-method}},
\code{\link{drill_jdbc}()}
}
\concept{Drill JDBC API}
\keyword{internal}

M man/sergeant-caffeinated-exports.Rd => man/sergeant-caffeinated-exports.Rd +0 -1
@@ 3,7 3,6 @@
\name{sergeant-caffeinated-exports}
\alias{sergeant-caffeinated-exports}
\alias{\%>\%}
\alias{tbl}
\title{sergeant exported operators}
\description{
The following functions are imported and then re-exported

M man/sergeant.caffeinated.Rd => man/sergeant.caffeinated.Rd +3 -4
@@ 23,14 23,13 @@ processing. At the core of Drill is the "Drillbit" service which is responsible 
accepting requests from the client, processing the queries, and returning results to
the client.

You can install and run a Drillbit service on one node or on many nodes to form a
distributed cluster environment. When a Drillbit runs on each data node in a cluster,
You can install and run a drillbit service on one node or on many nodes to form a
distributed cluster environment. When a drillbit runs on each data node in a cluster,
Drill can maximize data locality during query execution without moving data over the
network or between nodes. Drill uses ZooKeeper to maintain cluster membership and health
check information.

Methods are provided to work with Drill via the native JDBC & REST APIs along with R
\code{DBI} and \code{dplyr} interfaces.
An RDBC interface with a thin set of 'dbplyr` helper functions is provided.
}
\references{
\href{https://drill.apache.org/docs/}{Drill documentation}

A man/sql_translate_env.DrillJDBCConnection.Rd => man/sql_translate_env.DrillJDBCConnection.Rd +15 -0
@@ 0,0 1,15 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/new-jdbc.R
\name{sql_translate_env.DrillJDBCConnection}
\alias{sql_translate_env.DrillJDBCConnection}
\title{Thin wrapper for sql_translate_env}
\usage{
\method{sql_translate_env}{DrillJDBCConnection}(con)
}
\arguments{
\item{con}{connection}
}
\description{
Thin wrapper for sql_translate_env
}
\keyword{internal}

D tests/testthat.R => tests/testthat.R +0 -5
@@ 1,5 0,0 @@
library(dbplyr)
library(sergeant.caffeinated)
library(testthat)

test_check("sergeant.caffeinated")

D tests/testthat/test-sergeant.caffeinated.R => tests/testthat/test-sergeant.caffeinated.R +0 -17
@@ 1,17 0,0 @@
test_host <- Sys.getenv("DRILL_TEST_HOST", "localhost")

context("JDBC")
test_that("Core dbplyr ops work", {

  testthat::skip_on_cran()

  db <- src_drill_jdbc(test_host)

  expect_that(db, is_a("src_drill_jdbc"))

  test_dplyr <- tbl(db, "cp.`employee.json`")

  expect_that(test_dplyr, is_a("tbl"))
  expect_that(dplyr::count(test_dplyr, gender), is_a("tbl"))

})

A tests/tinytest.R => tests/tinytest.R +5 -0
@@ 0,0 1,5 @@

if ( requireNamespace("tinytest", quietly=TRUE) ){
  tinytest::test_package("sergeant.caffeinated")
}