Added R methods and their c counterparts for connection and database management

This commit is contained in:
2020-10-02 13:12:03 +01:00
parent 91013ea064
commit 907d848791
19 changed files with 847 additions and 28 deletions

7
src/Makevars.in Normal file
View 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
View 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
View 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
View 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
View 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
View 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);
}

View File

@@ -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;
}

View File

@@ -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__