Added R methods and their c counterparts for connection and database management
This commit is contained in:
23
NAMESPACE
23
NAMESPACE
@@ -1,2 +1,25 @@
|
||||
# Generated by roxygen2: do not edit by hand
|
||||
|
||||
export(TYPE_BLOB)
|
||||
export(TYPE_BOOL)
|
||||
export(TYPE_DOUBLE)
|
||||
export(TYPE_FLOAT)
|
||||
export(TYPE_INT16)
|
||||
export(TYPE_INT32)
|
||||
export(TYPE_INT64)
|
||||
export(TYPE_INT8)
|
||||
export(TYPE_RAW)
|
||||
export(TYPE_STRING)
|
||||
export(TYPE_TIMESTAMP)
|
||||
export(TYPE_UINT16)
|
||||
export(TYPE_UINT32)
|
||||
export(TYPE_UINT64)
|
||||
export(TYPE_UINT8)
|
||||
export(modb_conn_ref)
|
||||
export(modb_connect)
|
||||
export(modb_connectionExists)
|
||||
export(modb_connectionId)
|
||||
export(modb_connectionInfo)
|
||||
export(modb_connectionName)
|
||||
export(modb_disconnect)
|
||||
useDynLib(rmodb, .registration = TRUE, .fixes = "c_")
|
||||
|
||||
30
R/Defines.R
Normal file
30
R/Defines.R
Normal file
@@ -0,0 +1,30 @@
|
||||
#' @export
|
||||
TYPE_RAW <- bitwShiftL(0, 0)
|
||||
#' @export
|
||||
TYPE_BOOL <- bitwShiftL(1, 0)
|
||||
#' @export
|
||||
TYPE_INT8 <- bitwShiftL(1, 1)
|
||||
#' @export
|
||||
TYPE_UINT8 <- bitwShiftL(1, 2)
|
||||
#' @export
|
||||
TYPE_INT16 <- bitwShiftL(1, 3)
|
||||
#' @export
|
||||
TYPE_UINT16 <- bitwShiftL(1, 4)
|
||||
#' @export
|
||||
TYPE_INT32 <- bitwShiftL(1, 5)
|
||||
#' @export
|
||||
TYPE_UINT32 <- bitwShiftL(1, 6)
|
||||
#' @export
|
||||
TYPE_INT64 <- bitwShiftL(1, 7)
|
||||
#' @export
|
||||
TYPE_UINT64 <- bitwShiftL(1, 8)
|
||||
#' @export
|
||||
TYPE_FLOAT <- bitwShiftL(1, 9)
|
||||
#' @export
|
||||
TYPE_DOUBLE <- bitwShiftL(1, 10)
|
||||
#' @export
|
||||
TYPE_STRING <- bitwShiftL(1, 11)
|
||||
#' @export
|
||||
TYPE_BLOB <- bitwShiftL(1, 12)
|
||||
#' @export
|
||||
TYPE_TIMESTAMP <- bitwShiftL(1, 13)
|
||||
226
R/Manage.R
Normal file
226
R/Manage.R
Normal file
@@ -0,0 +1,226 @@
|
||||
|
||||
# Connection management --------------------------------------------------------
|
||||
|
||||
#' MODB Connection References
|
||||
#'
|
||||
#' \code{modb_conn_ref} checks for and/or validates parameters that may be a
|
||||
#' connection reference. Connections in MODB may be named on creation or must
|
||||
#' be referenced by the unique ID that is returned by the
|
||||
#' \link{\code{modb_connect}} method.
|
||||
#'
|
||||
#' @param conn_id Integer. The ID of the connection returned by modb_connect
|
||||
#' @param conn_name String. The name provided when creating a connection.
|
||||
#' @param conn_ref Expected to be either a conn_id or a conn_name
|
||||
#' @param args list(...) Arguments passed to a calling function in the va scope.
|
||||
#' @seealso \link{\code{modb_connect}}
|
||||
#' @export
|
||||
modb_conn_ref <- function(conn_id, conn_name, conn_ref, args = NULL) {
|
||||
if (length(args) != 0) {
|
||||
if ("conn_ref" %in% ls(args)) {
|
||||
conn_ref <- args$conn_ref
|
||||
}
|
||||
if ("conn_id" %in% ls(args)) {
|
||||
conn_id <- args$conn_id
|
||||
}
|
||||
if ("conn_name" %in% ls(args)) {
|
||||
conn_name <- args$conn_name
|
||||
}
|
||||
}
|
||||
|
||||
if (!missing(conn_ref)) {
|
||||
if (checkmate::test_string(conn_ref)) {
|
||||
return(conn_ref)
|
||||
} else if (checkmate::test_int(conn_ref)) {
|
||||
return(as.integer(conn_ref))
|
||||
} else {
|
||||
stop("invalid connection ref provided (must be string(name) or int(id))")
|
||||
}
|
||||
} else if (!missing(conn_id)) {
|
||||
if (!checkmate::test_null(conn_id)) {
|
||||
checkmate::assert_int(conn_id)
|
||||
return(as.integer(conn_id))
|
||||
}
|
||||
} else if (!missing(conn_name)) {
|
||||
if (!checkmate::test_null(conn_name)) {
|
||||
checkmate::assert_string(conn_name)
|
||||
return(conn_name)
|
||||
}
|
||||
}
|
||||
|
||||
stop("one of the arguments \"conn_ref\", \"conn_id\" or \"conn_name\" must be provided")
|
||||
}
|
||||
|
||||
|
||||
#' MODB Connections
|
||||
#'
|
||||
#' \code{modb_connect} creates a new database connection and attmepts to open a
|
||||
#' connection to a database with the details provided.
|
||||
#'
|
||||
#' @param username String. Username to use when connecting to the database.
|
||||
#' @param password String. Password to use when connecting to the database.
|
||||
#' @param database String. The database to use.
|
||||
#' @param host String. The hostname or IP address to connect to.
|
||||
#' Either host & port or socket may be used
|
||||
#' @param port Integer. The port number to connect on.
|
||||
#' @param socket String. The socket path to connect to,
|
||||
#' e.g. /var/run/mysqld/mysqld.sock
|
||||
#' @param name String. A name for the connection which can be used to identify
|
||||
#' the connection later on. Alternatively the id returned
|
||||
#' can be used.
|
||||
#' @return The id of the connection
|
||||
#' @export
|
||||
modb_connect <- function(username, password, database,
|
||||
host = "localhost", port = 3306,
|
||||
socket = NULL, conn_name = NULL) {
|
||||
checkmate::assert_string(username)
|
||||
checkmate::assert_string(password)
|
||||
checkmate::assert_string(database)
|
||||
|
||||
if (checkmate::test_null(socket)) {
|
||||
checkmate::assert_string(host)
|
||||
checkmate::assert_int(port, lower = 1, upper = 65535)
|
||||
res <- .Call(
|
||||
c_modb_connectToHost,
|
||||
conn_name,
|
||||
host,
|
||||
as.integer(port),
|
||||
username,
|
||||
password,
|
||||
database
|
||||
)
|
||||
} else {
|
||||
res <- .Call(
|
||||
c_modb_connectToSocket, conn_name, socket, username, password, database
|
||||
)
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
stop("failed to create connection")
|
||||
}
|
||||
|
||||
return(res)
|
||||
}
|
||||
|
||||
#' MODB Connections
|
||||
#'
|
||||
#' modb_disconnect closes a database connection and cleans up the instance
|
||||
#'
|
||||
#' @param ... conn_id, conn_name or conn_ref required. See \link{modb_conn_ref}
|
||||
#' @export
|
||||
modb_disconnect <- function(...) {
|
||||
res <- .Call(c_modb_disconnect, modb_conn_ref(args = list(...)))
|
||||
return(invisible(res))
|
||||
}
|
||||
|
||||
#' MODB Connections
|
||||
#'
|
||||
#' Fetches information on a connection such as the last query, insert id and
|
||||
#' number of queries run
|
||||
#'
|
||||
#' @param ... conn_id, conn_name or conn_ref required. See \link{modb_conn_ref}
|
||||
#' @return The details of the connection as a list.
|
||||
#' @export
|
||||
modb_connectionInfo <- function(stop_on_error = TRUE, ...) {
|
||||
conn_ref <- modb_conn_ref(args = list(...))
|
||||
utils::str(conn_ref)
|
||||
res <- .Call(c_modb_connectionInfo, conn_ref)
|
||||
|
||||
if (length(res) == sum(is.na(res))) {
|
||||
if (stop_on_error) {
|
||||
stop("invalid connection reference")
|
||||
} else {
|
||||
warning("invalid connection reference")
|
||||
return(NA)
|
||||
}
|
||||
}
|
||||
|
||||
return(res)
|
||||
}
|
||||
|
||||
#' @describeIn modb_connectionInfo Determines if a connection with the name or
|
||||
#' id provided exists
|
||||
#' @param ... conn_id, conn_name or conn_ref required. See \link{modb_conn_ref}
|
||||
#' @return TRUE if the connection exists, FALSE if not.
|
||||
#' @export
|
||||
modb_connectionExists <- function(...) {
|
||||
res <- .Call(c_modb_connectionInfo, modb_conn_ref(args = list(...)))
|
||||
return(!(length(res) == sum(is.na(res))))
|
||||
}
|
||||
|
||||
#' @describeIn modb_connectionInfo Finds a connection id via the name
|
||||
#' @param conn_name String. The name provided when creating a connection.
|
||||
#' @return The ID of the connection.
|
||||
#' @export
|
||||
modb_connectionId <- function(conn_name, stop_on_error = TRUE) {
|
||||
info <- modb_connectionInfo(stop_on_error, conn_ref = conn_name)
|
||||
if (length(info) == sum(is.na(info))) {
|
||||
return(NA)
|
||||
}
|
||||
return(info$id)
|
||||
}
|
||||
#' @describeIn modb_connectionInfo Finds a connection name via the id
|
||||
#' @param conn_id Integer. The id of the connection, returned by modb_connect.
|
||||
#' @return The name of the connection.
|
||||
#' @export
|
||||
modb_connectionName <- function(conn_id, stop_on_error = TRUE) {
|
||||
info <- modb_connectionInfo(stop_on_error, conn_ref = conn_id)
|
||||
if (length(info) == sum(is.na(info))) {
|
||||
return(NA)
|
||||
}
|
||||
return(info$name)
|
||||
}
|
||||
|
||||
|
||||
# Database management ----------------------------------------------------------
|
||||
|
||||
#' @export
|
||||
modb_exists <- function(modb_name, ...) {
|
||||
conn_ref <- modb_conn_ref(args = list(...))
|
||||
res <- .Call(c_modb_exists, conn_ref, modb_name)
|
||||
return(res)
|
||||
}
|
||||
#' @export
|
||||
modb_create <- function(modb_name, extended_meta = NULL, ...) {
|
||||
checkmate::assert_string(modb_name)
|
||||
|
||||
# If a dataframe: data.frame(name = c(1, 2, 3), type = c('a', 'b', 'c'), nullable = c(1,0,1), stringsAsFactors=F)
|
||||
# extended_meta %>% rowwise() %>% transmute(r = list(c("A" = A, "B" = B, "C" = C))) %>% first()
|
||||
if (!checkmate::test_null(extended_meta)) {
|
||||
for (idx in 1:length(extended_meta)) {
|
||||
meta_col <- extended_meta[[idx]]
|
||||
|
||||
if (!("name" %in% names(meta_col))) {
|
||||
stop("missing name in extended_meta definition")
|
||||
} else {
|
||||
checkmate::assert_string(meta_col$name)
|
||||
}
|
||||
|
||||
if (!("type" %in% names(meta_col))) {
|
||||
stop("missing type in extended_meta definition")
|
||||
} else {
|
||||
type <- meta_col$type
|
||||
checkmate::assert_int(type, lower = 0, upper = TYPE_TIMESTAMP)
|
||||
checkmate::assert_true(type == 1 || type %% 2 == 0)
|
||||
meta_col$type <- as.integer(type)
|
||||
}
|
||||
|
||||
if (!("nullable" %in% names(meta_col))) {
|
||||
meta_col$nullable = FALSE
|
||||
} else {
|
||||
checkmate::assert_logical(meta_col$nullable)
|
||||
}
|
||||
|
||||
extended_meta[[idx]] <- meta_col
|
||||
}
|
||||
}
|
||||
|
||||
conn_ref <- modb_conn_ref(args = list(...))
|
||||
res <- .Call(c_modb_create, conn_ref, modb_name, extended_meta)
|
||||
return(res)
|
||||
}
|
||||
#' @export
|
||||
modb_destroy <- function(modb_name, ...) {
|
||||
conn_ref <- modb_conn_ref(args = list(...))
|
||||
res <- .Call(c_modb_destroy, conn_ref, modb_name)
|
||||
return(res)
|
||||
}
|
||||
20
R/RMODB.R
Normal file
20
R/RMODB.R
Normal file
@@ -0,0 +1,20 @@
|
||||
#' RMODB: Metadata-Object pair database
|
||||
#'
|
||||
#' RMODB implements a metadata-object database for storing R objects in
|
||||
#' MySQL. R objects are serialized into a binary memory buffer which is then
|
||||
#' written into a MySQL database along with metadata such as creation
|
||||
#' timestamp, update timestamp, owner, title etc. The metadata fields are
|
||||
#' customisable on creation of the database. the metadata fields are cleartext
|
||||
#' and queryable allowing objects to be found and returned. On returning an
|
||||
#' object, it is de-serialised using the reverseof the serialize to binary
|
||||
#' memory process.
|
||||
#'
|
||||
#' @docType package
|
||||
#' @name rmodb
|
||||
#' @useDynLib rmodb, .registration = TRUE, .fixes = "c_"
|
||||
NULL
|
||||
#> NULL
|
||||
|
||||
.onUnload <- function(nspath) {
|
||||
# clear all connections
|
||||
}
|
||||
81
configure
vendored
Executable file
81
configure
vendored
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# Anticonf script by Jeroen Ooms (2020)
|
||||
# The script will try 'mariadb_config' and 'mysql_config' to find required
|
||||
# cflags and ldflags. Make sure this executable is in PATH when installing
|
||||
# the package. Alternatively, you can set INCLUDE_DIR and LIB_DIR manually:
|
||||
# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib'
|
||||
|
||||
# Library settings
|
||||
PKG_DEB_NAME="libmariadbclient-dev | libmariadb-client-lgpl-dev"
|
||||
PKG_RPM_NAME="mariadb-connector-c-devel | mariadb-devel | mysql-devel"
|
||||
PKG_CSW_NAME="mysql56_dev"
|
||||
PKG_BREW_NAME="mariadb-connector-c"
|
||||
PKG_TEST_HEADER="<mysql.h>"
|
||||
PKG_LIBS="-lmysqlclient"
|
||||
|
||||
# Use mysql_config (on Solaris /opt/csw/bin must be in PATH)
|
||||
if [ $(command -v mariadb_config) ]; then
|
||||
PKGCONFIG_CFLAGS=$(mariadb_config --cflags)
|
||||
PKGCONFIG_LIBS=$(mariadb_config --libs)
|
||||
elif [ $(command -v mysql_config) ]; then
|
||||
PKGCONFIG_CFLAGS=$(mysql_config --cflags)
|
||||
PKGCONFIG_LIBS=$(mysql_config --libs)
|
||||
fi
|
||||
|
||||
# Note that cflags may be empty in case of success
|
||||
if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then
|
||||
echo "Found INCLUDE_DIR and/or LIB_DIR!"
|
||||
PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS"
|
||||
PKG_LIBS="-L$LIB_DIR $PKG_LIBS"
|
||||
elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then
|
||||
echo "Found mysql_config cflags and libs!"
|
||||
PKG_CFLAGS=${PKGCONFIG_CFLAGS}
|
||||
PKG_LIBS=${PKGCONFIG_LIBS}
|
||||
# Workaround for homebrew linkin bug
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
PKG_LIBS="-L/usr/local/opt/openssl/lib $PKG_LIBS"
|
||||
fi
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
if [ $(command -v brew) ]; then
|
||||
BREWDIR=$(brew --prefix)
|
||||
else
|
||||
curl -sfL "https://jeroen.github.io/autobrew/$PKG_BREW_NAME" > autobrew
|
||||
source autobrew
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find compiler
|
||||
CC=$(${R_HOME}/bin/R CMD config CC)
|
||||
CFLAGS=$(${R_HOME}/bin/R CMD config CFLAGS)
|
||||
CPPFLAGS=$(${R_HOME}/bin/R CMD config CPPFLAGS)
|
||||
|
||||
# For debugging
|
||||
echo "Using PKG_CFLAGS=$PKG_CFLAGS"
|
||||
echo "Using PKG_LIBS=$PKG_LIBS"
|
||||
|
||||
# Test configuration
|
||||
echo "#include $PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null 2> configure.log
|
||||
|
||||
# Customize the error
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "-----------------------------[ ANTICONF ]-----------------------------"
|
||||
echo "Configure could not find suitable mysql/mariadb client library. Try installing:"
|
||||
echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu)"
|
||||
echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)"
|
||||
echo " * csw: $PKG_CSW_NAME (Solaris)"
|
||||
echo " * brew: $PKG_BREW_NAME (OSX)"
|
||||
echo "If you already have a mysql client library installed, verify that either"
|
||||
echo "mariadb_config or mysql_config is on your PATH. If these are unavailable"
|
||||
echo "you can also set INCLUDE_DIR and LIB_DIR manually via:"
|
||||
echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'"
|
||||
echo "--------------------------[ ERROR MESSAGE ]----------------------------"
|
||||
cat configure.log
|
||||
echo "-----------------------------------------------------------------------"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Write to Makevars
|
||||
sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars
|
||||
|
||||
# Success
|
||||
exit 0
|
||||
26
man/modb_conn_ref.Rd
Normal file
26
man/modb_conn_ref.Rd
Normal file
@@ -0,0 +1,26 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/Manage.R
|
||||
\name{modb_conn_ref}
|
||||
\alias{modb_conn_ref}
|
||||
\title{MODB Connection References}
|
||||
\usage{
|
||||
modb_conn_ref(conn_id, conn_name, conn_ref, args = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{conn_id}{Integer. The ID of the connection returned by modb_connect}
|
||||
|
||||
\item{conn_name}{String. The name provided when creating a connection.}
|
||||
|
||||
\item{conn_ref}{Expected to be either a conn_id or a conn_name}
|
||||
|
||||
\item{args}{list(...) Arguments passed to a calling function in the va scope.}
|
||||
}
|
||||
\description{
|
||||
\code{modb_conn_ref} checks for and/or validates parameters that may be a
|
||||
connection reference. Connections in MODB may be named on creation or must
|
||||
be referenced by the unique ID that is returned by the
|
||||
\link{\code{modb_connect}} method.
|
||||
}
|
||||
\seealso{
|
||||
\link{\code{modb_connect}}
|
||||
}
|
||||
42
man/modb_connect.Rd
Normal file
42
man/modb_connect.Rd
Normal file
@@ -0,0 +1,42 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/Manage.R
|
||||
\name{modb_connect}
|
||||
\alias{modb_connect}
|
||||
\title{MODB Connections}
|
||||
\usage{
|
||||
modb_connect(
|
||||
username,
|
||||
password,
|
||||
database,
|
||||
host = "localhost",
|
||||
port = 3306,
|
||||
socket = NULL,
|
||||
conn_name = NULL
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{username}{String. Username to use when connecting to the database.}
|
||||
|
||||
\item{password}{String. Password to use when connecting to the database.}
|
||||
|
||||
\item{database}{String. The database to use.}
|
||||
|
||||
\item{host}{String. The hostname or IP address to connect to.
|
||||
Either host & port or socket may be used}
|
||||
|
||||
\item{port}{Integer. The port number to connect on.}
|
||||
|
||||
\item{socket}{String. The socket path to connect to,
|
||||
e.g. /var/run/mysqld/mysqld.sock}
|
||||
|
||||
\item{name}{String. A name for the connection which can be used to identify
|
||||
the connection later on. Alternatively the id returned
|
||||
can be used.}
|
||||
}
|
||||
\value{
|
||||
The id of the connection
|
||||
}
|
||||
\description{
|
||||
\code{modb_connect} creates a new database connection and attmepts to open a
|
||||
connection to a database with the details provided.
|
||||
}
|
||||
47
man/modb_connectionInfo.Rd
Normal file
47
man/modb_connectionInfo.Rd
Normal file
@@ -0,0 +1,47 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/Manage.R
|
||||
\name{modb_connectionInfo}
|
||||
\alias{modb_connectionInfo}
|
||||
\alias{modb_connectionExists}
|
||||
\alias{modb_connectionId}
|
||||
\alias{modb_connectionName}
|
||||
\title{MODB Connections}
|
||||
\usage{
|
||||
modb_connectionInfo(stop_on_error = TRUE, ...)
|
||||
|
||||
modb_connectionExists(...)
|
||||
|
||||
modb_connectionId(conn_name, stop_on_error = TRUE)
|
||||
|
||||
modb_connectionName(conn_id, stop_on_error = TRUE)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{conn_id, conn_name or conn_ref required. See \link{modb_conn_ref}}
|
||||
|
||||
\item{conn_name}{String. The name provided when creating a connection.}
|
||||
|
||||
\item{conn_id}{Integer. The id of the connection, returned by modb_connect.}
|
||||
}
|
||||
\value{
|
||||
The details of the connection as a list.
|
||||
|
||||
TRUE if the connection exists, FALSE if not.
|
||||
|
||||
The ID of the connection.
|
||||
|
||||
The name of the connection.
|
||||
}
|
||||
\description{
|
||||
Fetches information on a connection such as the last query, insert id and
|
||||
number of queries run
|
||||
}
|
||||
\section{Functions}{
|
||||
\itemize{
|
||||
\item \code{modb_connectionExists}: Determines if a connection with the name or
|
||||
id provided exists
|
||||
|
||||
\item \code{modb_connectionId}: Finds a connection id via the name
|
||||
|
||||
\item \code{modb_connectionName}: Finds a connection name via the id
|
||||
}}
|
||||
|
||||
14
man/modb_disconnect.Rd
Normal file
14
man/modb_disconnect.Rd
Normal file
@@ -0,0 +1,14 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/Manage.R
|
||||
\name{modb_disconnect}
|
||||
\alias{modb_disconnect}
|
||||
\title{MODB Connections}
|
||||
\usage{
|
||||
modb_disconnect(...)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{conn_id, conn_name or conn_ref required. See \link{modb_conn_ref}}
|
||||
}
|
||||
\description{
|
||||
modb_disconnect closes a database connection and cleans up the instance
|
||||
}
|
||||
16
man/rmodb.Rd
Normal file
16
man/rmodb.Rd
Normal file
@@ -0,0 +1,16 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/RMODB.R
|
||||
\docType{package}
|
||||
\name{rmodb}
|
||||
\alias{rmodb}
|
||||
\title{RMODB: Metadata-Object pair database}
|
||||
\description{
|
||||
RMODB implements a metadata-object database for storing R objects in
|
||||
MySQL. R objects are serialized into a binary memory buffer which is then
|
||||
written into a MySQL database along with metadata such as creation
|
||||
timestamp, update timestamp, owner, title etc. The metadata fields are
|
||||
customisable on creation of the database. the metadata fields are cleartext
|
||||
and queryable allowing objects to be found and returned. On returning an
|
||||
object, it is de-serialised using the reverseof the serialize to binary
|
||||
memory process.
|
||||
}
|
||||
7
src/Makevars.in
Normal file
7
src/Makevars.in
Normal file
@@ -0,0 +1,7 @@
|
||||
PKG_CPPFLAGS=@cflags@
|
||||
PKG_LIBS=@libs@
|
||||
|
||||
all: clean
|
||||
|
||||
clean:
|
||||
rm -f $(SHLIB) $(OBJECTS)
|
||||
22
src/R_list_item.c
Normal file
22
src/R_list_item.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "R_list_item.h"
|
||||
|
||||
SEXP R_listItem(SEXP list, const char *name)
|
||||
{
|
||||
SEXP r_names = Rf_getAttrib(list, R_NamesSymbol);
|
||||
SEXP r_name;
|
||||
|
||||
for (int i = 0; i < Rf_length(list); i++) {
|
||||
if (TYPEOF(r_names) == STRSXP) {
|
||||
r_name = STRING_ELT(r_names, i);
|
||||
} else {
|
||||
r_name = VECTOR_ELT(r_names, i);
|
||||
}
|
||||
if (strcmp(Rf_translateCharUTF8(r_name), name) == 0) {
|
||||
return VECTOR_ELT(list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return R_NilValue;
|
||||
}
|
||||
8
src/R_list_item.h
Normal file
8
src/R_list_item.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef H__R_LIST_ITEM__
|
||||
#define H__R_LIST_ITEM__
|
||||
|
||||
#include <Rinternals.h>
|
||||
|
||||
SEXP R_listItem(SEXP list, const char *name);
|
||||
|
||||
#endif // H__R_LIST_ITEM__
|
||||
240
src/R_modb_manage.c
Normal file
240
src/R_modb_manage.c
Normal file
@@ -0,0 +1,240 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "R_modb_manage.h"
|
||||
#include "R_list_item.h"
|
||||
#include "db_connection.h"
|
||||
#include "modb.h"
|
||||
|
||||
|
||||
struct stored_conn_t *getConn(SEXP r_conn_ref)
|
||||
{
|
||||
struct stored_conn_t *sconn = 0;
|
||||
|
||||
if (Rf_isString(r_conn_ref)) {
|
||||
sconn = connectionByName(Rf_translateCharUTF8(STRING_ELT(r_conn_ref, 0)));
|
||||
} else if (Rf_isInteger(r_conn_ref)) {
|
||||
sconn = connectionById(Rf_asInteger(r_conn_ref));
|
||||
} else {
|
||||
Rf_error("Neither name or id provided");
|
||||
}
|
||||
|
||||
return sconn;
|
||||
}
|
||||
|
||||
|
||||
SEXP modb_connectionInfo(SEXP r_conn_ref)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
SEXP res, conn_name, last_qry, names;
|
||||
|
||||
if ((sconn = getConn(r_conn_ref)) == 0) {
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
conn_name = PROTECT(Rf_allocVector(STRSXP, 1));
|
||||
SET_STRING_ELT(conn_name, 0, PROTECT(Rf_mkChar(sconn->name)));
|
||||
|
||||
last_qry = PROTECT(Rf_allocVector(STRSXP, 1));
|
||||
if (sconn->last_qry != 0) {
|
||||
SET_STRING_ELT(last_qry, 0, PROTECT(Rf_mkChar(sconn->last_qry)));
|
||||
} else {
|
||||
SET_STRING_ELT(last_qry, 0, PROTECT(NA_STRING));
|
||||
}
|
||||
|
||||
res = PROTECT(Rf_allocVector(VECSXP, 4));
|
||||
SET_VECTOR_ELT(res, 0, PROTECT(Rf_ScalarInteger(sconn->conn_id)));
|
||||
SET_VECTOR_ELT(res, 1, conn_name);
|
||||
SET_VECTOR_ELT(res, 2, last_qry);
|
||||
SET_VECTOR_ELT(res, 3, PROTECT(Rf_ScalarInteger((int)sconn->num_queries)));
|
||||
|
||||
names = PROTECT(Rf_allocVector(STRSXP, 4));
|
||||
SET_STRING_ELT(names, 0, PROTECT(Rf_mkChar("id")));
|
||||
SET_STRING_ELT(names, 1, PROTECT(Rf_mkChar("name")));
|
||||
SET_STRING_ELT(names, 2, PROTECT(Rf_mkChar("num_queries")));
|
||||
SET_STRING_ELT(names, 3, PROTECT(Rf_mkChar("last_query")));
|
||||
Rf_setAttrib(res, R_NamesSymbol, names);
|
||||
|
||||
UNPROTECT(12);
|
||||
return res;
|
||||
}
|
||||
|
||||
SEXP modb_connectToHost(SEXP r_name, SEXP r_host, SEXP r_port,
|
||||
SEXP r_username, SEXP r_password, SEXP r_database)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
const char *name = 0, *host, *user, *pass, *db;
|
||||
unsigned int port;
|
||||
|
||||
if (!Rf_isNull(r_name)) {
|
||||
name = Rf_translateCharUTF8(STRING_ELT(r_name, 0));
|
||||
}
|
||||
|
||||
host = Rf_translateCharUTF8(STRING_ELT(r_host, 0));
|
||||
port = (unsigned int)Rf_asInteger(r_port);
|
||||
user = Rf_translateCharUTF8(STRING_ELT(r_username, 0));
|
||||
pass = Rf_translateCharUTF8(STRING_ELT(r_password, 0));
|
||||
db = Rf_translateCharUTF8(STRING_ELT(r_database, 0));
|
||||
|
||||
sconn = createStoredConnection(name);
|
||||
if (sconn == 0) {
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
if (connectToHost(sconn, host, port, user, pass, db) < 0) {
|
||||
destroyStoredConnection(sconn);
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
return Rf_ScalarInteger(sconn->conn_id);
|
||||
}
|
||||
SEXP modb_connectToSocket(SEXP r_name, SEXP r_socket,
|
||||
SEXP r_username, SEXP r_password, SEXP r_database)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
const char *name = 0, *sock, *user, *pass, *db;
|
||||
|
||||
if (!Rf_isNull(r_name)) {
|
||||
name = Rf_translateCharUTF8(STRING_ELT(r_name, 0));
|
||||
}
|
||||
|
||||
sock = Rf_translateCharUTF8(STRING_ELT(r_socket, 0));
|
||||
user = Rf_translateCharUTF8(STRING_ELT(r_username, 0));
|
||||
pass = Rf_translateCharUTF8(STRING_ELT(r_password, 0));
|
||||
db = Rf_translateCharUTF8(STRING_ELT(r_database, 0));
|
||||
|
||||
sconn = createStoredConnection(name);
|
||||
if (sconn == 0) {
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
if (connectToSocket(sconn, sock, user, pass, db) < 0) {
|
||||
destroyStoredConnection(sconn);
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
return Rf_ScalarInteger(sconn->conn_id);
|
||||
}
|
||||
|
||||
SEXP modb_disconnect(SEXP r_conn_ref)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
int conn_id;
|
||||
|
||||
if ((sconn = getConn(r_conn_ref)) == 0) {
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
conn_id = sconn->conn_id;
|
||||
|
||||
closeConnection(sconn);
|
||||
destroyStoredConnection(sconn);
|
||||
|
||||
return Rf_ScalarInteger(conn_id);
|
||||
}
|
||||
|
||||
|
||||
SEXP modb_exists(SEXP r_conn_ref, SEXP r_name)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
struct modb_t modb;
|
||||
|
||||
if ((sconn = getConn(r_conn_ref)) == 0) {
|
||||
Rf_error("invalid connection reference\n");
|
||||
}
|
||||
|
||||
modb.name = Rf_translateCharUTF8(STRING_ELT(r_name, 0));
|
||||
modb.name_len = strlen(modb.name);
|
||||
|
||||
return Rf_ScalarLogical(modbExists(sconn, &modb) > 0);
|
||||
}
|
||||
SEXP modb_create(SEXP r_conn_ref, SEXP r_name, SEXP r_extra_meta)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
struct modb_t modb;
|
||||
struct column_data_t **cols;
|
||||
size_t n_cols;
|
||||
SEXP r_col, r_col_name, r_col_type, r_col_null;
|
||||
|
||||
if ((sconn = getConn(r_conn_ref)) == 0) {
|
||||
Rf_error("invalid connection reference\n");
|
||||
}
|
||||
|
||||
modb.name = Rf_translateCharUTF8(STRING_ELT(r_name, 0));
|
||||
modb.name_len = strlen(modb.name);
|
||||
|
||||
if (modbExists(sconn, &modb) == 0) {
|
||||
Rf_warning("an MODB instance named '%s' already exists\n", modb.name);
|
||||
return Rf_ScalarLogical(FALSE);
|
||||
}
|
||||
|
||||
if (modbCreate(sconn, &modb) != 0) {
|
||||
modb_destroy(r_conn_ref, r_name);
|
||||
Rf_warning("failed to create MODB instance");
|
||||
return Rf_ScalarLogical(FALSE);
|
||||
}
|
||||
if (modbAccountingCreate(sconn, &modb) != 0) {
|
||||
modb_destroy(r_conn_ref, r_name);
|
||||
Rf_warning("failed to create MODB instance");
|
||||
return Rf_ScalarLogical(FALSE);
|
||||
}
|
||||
if (!Rf_isNull(r_extra_meta)) {
|
||||
n_cols = (size_t)Rf_length(r_extra_meta);
|
||||
cols = (struct column_data_t **)calloc(sizeof(struct column_data_t *), n_cols);
|
||||
if (cols == 0) {
|
||||
modb_destroy(r_conn_ref, r_name);
|
||||
Rf_warning("failed to create MODB instance");
|
||||
return Rf_ScalarLogical(FALSE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n_cols; i++) {
|
||||
r_col = VECTOR_ELT(r_extra_meta, (int)i);
|
||||
r_col_name = STRING_ELT(R_listItem(r_col, "name"), 0);
|
||||
r_col_type = R_listItem(r_col, "type");
|
||||
r_col_null = R_listItem(r_col, "nullable");
|
||||
|
||||
*(cols + i) = initEmptyColumn(
|
||||
(e_column_type)(unsigned int)Rf_asInteger(r_col_type),
|
||||
Rf_asLogical(r_col_null),
|
||||
Rf_translateCharUTF8(r_col_name),
|
||||
0, 0, 0);
|
||||
if (*(cols + i) == 0) {
|
||||
freeColumns(cols, i);
|
||||
modb_destroy(r_conn_ref, r_name);
|
||||
Rf_warning("failed to create MODB instance");
|
||||
return Rf_ScalarLogical(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (modbMetaExtCreate(sconn, &modb, cols, n_cols) != 0) {
|
||||
freeColumns(cols, n_cols);
|
||||
modb_destroy(r_conn_ref, r_name);
|
||||
Rf_warning("failed to create MODB instance");
|
||||
return Rf_ScalarLogical(FALSE);
|
||||
}
|
||||
|
||||
freeColumns(cols, n_cols);
|
||||
}
|
||||
|
||||
return Rf_ScalarLogical(TRUE);
|
||||
}
|
||||
SEXP modb_destroy(SEXP r_conn_ref, SEXP r_name)
|
||||
{
|
||||
struct stored_conn_t *sconn;
|
||||
struct modb_t modb;
|
||||
|
||||
if ((sconn = getConn(r_conn_ref)) == 0) {
|
||||
Rf_error("invalid connection reference\n");
|
||||
}
|
||||
|
||||
modb.name = Rf_translateCharUTF8(STRING_ELT(r_name, 0));
|
||||
modb.name_len = strlen(modb.name);
|
||||
|
||||
if (modbMetaExtExists(sconn, &modb) > 0) {
|
||||
modbMetaExtDestroy(sconn, &modb);
|
||||
}
|
||||
modbAccountingDestroy(sconn, &modb);
|
||||
modbDestroy(sconn, &modb);
|
||||
|
||||
return Rf_ScalarLogical(TRUE);
|
||||
}
|
||||
20
src/R_modb_manage.h
Normal file
20
src/R_modb_manage.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef H__R_MODB_MANAGE__
|
||||
#define H__R_MODB_MANAGE__
|
||||
|
||||
#include <Rinternals.h>
|
||||
|
||||
SEXP modb_connectionInfo(SEXP r_conn_ref);
|
||||
|
||||
SEXP modb_connectToHost(SEXP r_name, SEXP r_host, SEXP r_port,
|
||||
SEXP r_username, SEXP r_password, SEXP r_database);
|
||||
SEXP modb_connectToSocket(SEXP r_name, SEXP r_socket,
|
||||
SEXP r_username, SEXP r_password, SEXP r_database);
|
||||
|
||||
SEXP modb_disconnect(SEXP r_conn_ref);
|
||||
|
||||
|
||||
SEXP modb_exists(SEXP r_conn_ref, SEXP r_name);
|
||||
SEXP modb_create(SEXP r_conn_ref, SEXP r_name, SEXP r_extra_meta);
|
||||
SEXP modb_destroy(SEXP r_conn_ref, SEXP r_name);
|
||||
|
||||
#endif // H__R_MODB_MANAGE__
|
||||
22
src/initR.c
Normal file
22
src/initR.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <Rinternals.h>
|
||||
|
||||
#include "R_modb_manage.h"
|
||||
|
||||
static const R_CallMethodDef callMethods[] = {
|
||||
{"modb_connectionInfo", (DL_FUNC) &modb_connectionInfo, 1},
|
||||
{"modb_connectToHost", (DL_FUNC) &modb_connectToHost, 6},
|
||||
{"modb_connectToSocket", (DL_FUNC) &modb_connectToSocket, 5},
|
||||
{"modb_disconnect", (DL_FUNC) &modb_disconnect, 1},
|
||||
|
||||
{"modb_exists", (DL_FUNC) &modb_exists, 2},
|
||||
{"modb_create", (DL_FUNC) &modb_create, 3},
|
||||
{"modb_destroy", (DL_FUNC) &modb_destroy, 2},
|
||||
{NULL, NULL, 0}
|
||||
};
|
||||
|
||||
void R_init_rmodb(DllInfo *dll)
|
||||
{
|
||||
R_registerRoutines(dll, NULL, callMethods, NULL, NULL);
|
||||
R_useDynamicSymbols(dll, FALSE);
|
||||
R_forceSymbols(dll, TRUE);
|
||||
}
|
||||
@@ -7,28 +7,3 @@
|
||||
#include "strext.h"
|
||||
|
||||
|
||||
struct modb_t *modbAlloc(const char *name, size_t name_len)
|
||||
{
|
||||
struct modb_t *modb = (struct modb_t *)malloc(sizeof(struct modb_t));
|
||||
if (modb == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strmemcpy(name, name_len, &modb->name, &modb->name_len) != 0) {
|
||||
modbRelease(&modb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return modb;
|
||||
}
|
||||
void modbRelease(struct modb_t **modb)
|
||||
{
|
||||
if ((*modb)->name != 0) {
|
||||
free((*modb)->name);
|
||||
(*modb)->name = 0;
|
||||
}
|
||||
|
||||
free(*modb);
|
||||
*modb = 0;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
#include <stdint.h>
|
||||
|
||||
struct modb_t {
|
||||
char *name;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
};
|
||||
|
||||
struct modb_t *modbAlloc(const char *name, size_t name_len);
|
||||
void modbRelease(struct modb_t **modb);
|
||||
|
||||
#endif // H__MODB_TYPES__
|
||||
|
||||
Reference in New Issue
Block a user