diff --git a/NAMESPACE b/NAMESPACE index 3a989db3..bea1797f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -27,6 +27,7 @@ export(mariadbHasDefault) exportClasses(MariaDBConnection) exportClasses(MariaDBDriver) exportClasses(MariaDBResult) +exportClasses(MySQLConnection) exportMethods(dbAppendTable) exportMethods(dbBegin) exportMethods(dbBind) diff --git a/R/MariaDBConnection.R b/R/MariaDBConnection.R index 7c4b627f..b531764c 100644 --- a/R/MariaDBConnection.R +++ b/R/MariaDBConnection.R @@ -1,11 +1,21 @@ #' Class MariaDBConnection. #' -#' `MariaDBConnection` objects are usually created by -#' [DBI::dbConnect()] +#' `"MariaDBConnection"` objects are usually created by [DBI::dbConnect()]. +#' They represent a connection to a MariaDB or MySQL database. +#' +#' The `"MySQLConnection"` class is a subclass of `"MariaDBConnection"`. +#' Objects of that class are created by `dbConnect(MariaDB(), ..., mysql = TRUE)` +#' to indicate that the server is a MySQL server. +#' The \pkg{RMariaDB} package supports both MariaDB and MySQL servers, but the SQL dialect +#' and other details vary. +#' The default is to detect the server type based on the version number. +#' +#' The older \pkg{RMySQL} package also implements the `"MySQLConnection"` class. +#' The S4 system is able to distinguish between \pkg{RMariaDB} and \pkg{RMySQL} objects +#' even if both packages are loaded. #' -#' @export #' @keywords internal -setClass("MariaDBConnection", +MariaDBConnection <- setClass("MariaDBConnection", contains = "DBIConnection", slots = list( ptr = "externalptr", @@ -18,6 +28,19 @@ setClass("MariaDBConnection", ) ) +#' @exportClass MariaDBConnection +NULL + +#' @keywords internal +#' @name MariaDBConnection-class +#' @aliases MySQLConnection-class +MySQLConnection <- setClass("MySQLConnection", + contains = "MariaDBConnection" +) + +#' @exportClass MySQLConnection +NULL + # format() #' @export #' @rdname MariaDBConnection-class diff --git a/R/dbConnect_MariaDBDriver.R b/R/dbConnect_MariaDBDriver.R index c0911889..dfa2ac44 100644 --- a/R/dbConnect_MariaDBDriver.R +++ b/R/dbConnect_MariaDBDriver.R @@ -80,6 +80,12 @@ #' @param reconnect (experimental) Set to `TRUE` to use `MYSQL_OPT_RECONNECT` to enable #' automatic reconnection. This is experimental and could be dangerous if the connection #' is lost in the middle of a transaction. +#' @param mysql Set to `TRUE`/`FALSE` to connect to a MySQL server or to a MariaDB server, +#' respectively. +#' The \pkg{RMariaDB} package supports both MariaDB and MySQL servers, but the SQL dialect +#' and other details vary. +#' The default is to assume MariaDB if the version is >= 10.0.0, and MySQL otherwise. +#' #' @references #' Configuration files: https://mariadb.com/kb/en/library/configuring-mariadb-with-mycnf/ #' @examples @@ -108,13 +114,31 @@ #' } #' @usage NULL #' @rdname dbConnect-MariaDBDriver-method -dbConnect_MariaDBDriver <- function(drv, dbname = NULL, username = NULL, password = NULL, host = NULL, - unix.socket = NULL, port = 0, client.flag = 0, - groups = "rs-dbi", default.file = NULL, ssl.key = NULL, ssl.cert = NULL, - ssl.ca = NULL, ssl.capath = NULL, ssl.cipher = NULL, ..., - load_data_local_infile = FALSE, - bigint = c("integer64", "integer", "numeric", "character"), - timeout = 10, timezone = "+00:00", timezone_out = NULL, reconnect = FALSE) { +dbConnect_MariaDBDriver <- function( + drv, + dbname = NULL, + username = NULL, + password = NULL, + host = NULL, + unix.socket = NULL, + port = 0, + client.flag = 0, + groups = "rs-dbi", + default.file = NULL, + ssl.key = NULL, + ssl.cert = NULL, + ssl.ca = NULL, + ssl.capath = NULL, + ssl.cipher = NULL, + ..., + load_data_local_infile = FALSE, + bigint = c("integer64", "integer", "numeric", "character"), + timeout = 10, + timezone = "+00:00", + timezone_out = NULL, + reconnect = FALSE, + mysql = NULL) { + # bigint <- match.arg(bigint) if (is.infinite(timeout)) { @@ -157,7 +181,17 @@ dbConnect_MariaDBDriver <- function(drv, dbname = NULL, username = NULL, passwor info <- connection_info(ptr) - conn <- new("MariaDBConnection", + if (is.null(mysql)) { + mysql <- (info$db.version.int < 100000) + } + + if (isTRUE(mysql)) { + new <- MySQLConnection + } else { + new <- MariaDBConnection + } + + conn <- new( ptr = ptr, host = info$host, db = info$dbname, diff --git a/R/default.R b/R/default.R index f848e1fe..1cbc9760 100644 --- a/R/default.R +++ b/R/default.R @@ -38,7 +38,30 @@ mariadbDefault <- function() { }, error = function(...) { testthat::skip("Test database not available") - }) + } + ) +} + +mysqlDefault <- function() { + tryCatch( + { + mariadb_default(mysql = TRUE) + }, + error = function(...) { + testthat::skip("Test database not available") + } + ) +} + +mariadbForceDefault <- function() { + tryCatch( + { + mariadb_default(mysql = FALSE) + }, + error = function(...) { + testthat::skip("Test database not available") + } + ) } mariadb_default <- function(...) { @@ -47,5 +70,8 @@ mariadb_default <- function(...) { mariadb_default_args <- as.list(c( dbname = "test", + # host = "192.168.64.2", + # user = "compose", + # password = "YourStrong!Passw0rd", NULL )) diff --git a/man/MariaDBConnection-class.Rd b/man/MariaDBConnection-class.Rd index 57d8f274..866109d4 100644 --- a/man/MariaDBConnection-class.Rd +++ b/man/MariaDBConnection-class.Rd @@ -5,6 +5,9 @@ \docType{class} \name{MariaDBConnection-class} \alias{MariaDBConnection-class} +\alias{MariaDBConnection} +\alias{MySQLConnection} +\alias{MySQLConnection-class} \alias{format.MariaDBConnection} \alias{dbDisconnect_MariaDBConnection} \alias{dbDisconnect,MariaDBConnection-method} @@ -27,7 +30,19 @@ \S4method{show}{MariaDBConnection}(object) } \description{ -\code{MariaDBConnection} objects are usually created by -\code{\link[DBI:dbConnect]{DBI::dbConnect()}} +\code{"MariaDBConnection"} objects are usually created by \code{\link[DBI:dbConnect]{DBI::dbConnect()}}. +They represent a connection to a MariaDB or MySQL database. +} +\details{ +The \code{"MySQLConnection"} class is a subclass of \code{"MariaDBConnection"}. +Objects of that class are created by \code{dbConnect(MariaDB(), ..., mysql = TRUE)} +to indicate that the server is a MySQL server. +The \pkg{RMariaDB} package supports both MariaDB and MySQL servers, but the SQL dialect +and other details vary. +The default is to detect the server type based on the version number. + +The older \pkg{RMySQL} package also implements the \code{"MySQLConnection"} class. +The S4 system is able to distinguish between \pkg{RMariaDB} and \pkg{RMySQL} objects +even if both packages are loaded. } \keyword{internal} diff --git a/man/dbConnect-MariaDBDriver-method.Rd b/man/dbConnect-MariaDBDriver-method.Rd index 5271afa7..cdf7cdbf 100644 --- a/man/dbConnect-MariaDBDriver-method.Rd +++ b/man/dbConnect-MariaDBDriver-method.Rd @@ -30,7 +30,8 @@ MariaDB() timeout = 10, timezone = "+00:00", timezone_out = NULL, - reconnect = FALSE + reconnect = FALSE, + mysql = NULL ) } \arguments{ @@ -109,6 +110,12 @@ This setting does not change the time values returned, only their display.} \item{reconnect}{(experimental) Set to \code{TRUE} to use \code{MYSQL_OPT_RECONNECT} to enable automatic reconnection. This is experimental and could be dangerous if the connection is lost in the middle of a transaction.} + +\item{mysql}{Set to \code{TRUE}/\code{FALSE} to connect to a MySQL server or to a MariaDB server, +respectively. +The \pkg{RMariaDB} package supports both MariaDB and MySQL servers, but the SQL dialect +and other details vary. +The default is to assume MariaDB if the version is >= 10.0.0, and MySQL otherwise.} } \description{ These methods are straight-forward implementations of the corresponding diff --git a/src/DbConnection.cpp b/src/DbConnection.cpp index cc738a7d..74602e6d 100644 --- a/src/DbConnection.cpp +++ b/src/DbConnection.cpp @@ -115,6 +115,7 @@ cpp11::list DbConnection::info() { "dbname"_nm = std::string(pConn_->db ? pConn_->db : ""), "con.type"_nm = std::string(mysql_get_host_info(pConn_)), "db.version"_nm = std::string(mysql_get_server_info(pConn_)), + "db.version.int"_nm = (int) mysql_get_server_version(pConn_), "port"_nm = NA_INTEGER, "protocol.version"_nm = (int) mysql_get_proto_info(pConn_), "thread.id"_nm = (int) mysql_thread_id(pConn_) diff --git a/tests/testthat/test-dbConnect.R b/tests/testthat/test-dbConnect.R new file mode 100644 index 00000000..f0dde1f3 --- /dev/null +++ b/tests/testthat/test-dbConnect.R @@ -0,0 +1,22 @@ +test_that("Connecting with mysql = FALSE", { + con <- mariadbForceDefault() + on.exit(dbDisconnect(con)) + + expect_s4_class(con, "MariaDBConnection") + expect_false(is(con, "MySQLConnection")) +}) + +test_that("Connecting with mysql = TRUE", { + con <- mysqlDefault() + on.exit(dbDisconnect(con)) + + expect_s4_class(con, "MariaDBConnection") + expect_s4_class(con, "MySQLConnection") +}) + +test_that("Connecting with mysql unset", { + con <- mariadbDefault() + on.exit(dbDisconnect(con)) + + expect_s4_class(con, "MariaDBConnection") +})