Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

- updated copyright statements

- Makefile fix for Mac OSX per kostas savvidis
- Added RPostgreSQL compatability functions
- Added ability to send serialized R objects to Postgres as bytea return values
- Added ability to convert bytea arguments from Postgres back into the original R object
- Added function to unserialize bytea value in order to restore object outside of R (useful for image data)
  • Loading branch information...
commit c7aa0e9ee73ce7901f11bf5475fe557834fc31fc 1 parent 2c727f3
jconway authored
View
4 Makefile
@@ -5,14 +5,14 @@ r_libdir1x = ${R_HOME}/bin
r_libdir2x = ${R_HOME}/lib
# location of R includes
r_includespec = ${R_HOME}/include
+rhomedef = ${R_HOME}
else
R_HOME := $(shell pkg-config --variable=rhome libR)
r_libdir1x := $(shell pkg-config --variable=rlibdir libR)
r_libdir2x := $(shell pkg-config --variable=rlibdir libR)
r_includespec := $(shell pkg-config --variable=rincludedir libR)
-endif
-
rhomedef := $(shell pkg-config --variable=rhome libR)
+endif
ifneq (,${R_HOME})
View
2  README.plr
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
View
120 doc/plr.sgml
@@ -3,7 +3,7 @@
<title>PL/R User's Guide - R Procedural Language</title>
<bookinfo>
<copyright>
- <year>2003-2007</year>
+ <year>2003-2009</year>
<holder>Joseph E Conway</holder>
</copyright>
</bookinfo>
@@ -313,12 +313,15 @@ select round(sd('{1.23,1.31,1.42,1.27}'::_float8)::numeric,8);
The argument values supplied to a PL/R function's script are
the input arguments converted to a corresponding R form.
See <xref linkend="plr-args-table">. Scalar PostgreSQL
- values become single element R vectors. One-dimensional
- PostgreSQL arrays are converted to multi-element R vectors, two-dimensional
- PostgreSQL arrays are mapped to R matrixes, and three-dimensional
- PostgreSQL arrays are converted to three-dimensional R arrays. Greater
- than three-dimensional arrays are not supported. Composite-types are
- transformed into R data.frames.
+ values become single element R vectors. One exception to
+ this are scalar bytea values. These are first converted to
+ R raw type, and then processed by the R unserialize command.
+ One-dimensional PostgreSQL arrays are converted to multi-element
+ R vectors, two-dimensional PostgreSQL arrays are mapped to R
+ matrixes, and three-dimensional PostgreSQL arrays are converted
+ to three-dimensional R arrays. Greater than three-dimensional
+ arrays are not supported. Composite-types are transformed into
+ R data.frames.
</para>
<table id="plr-args-table">
@@ -350,6 +353,11 @@ select round(sd('{1.23,1.31,1.42,1.27}'::_float8)::numeric,8);
</row>
<row>
+ <entry><type>bytea</type></entry>
+ <entry><type>object</type></entry>
+ </row>
+
+ <row>
<entry>everything else</entry>
<entry><type>character</type></entry>
</row>
@@ -362,6 +370,10 @@ select round(sd('{1.23,1.31,1.42,1.27}'::_float8)::numeric,8);
Conversely, the return values are first coerced to R character, and
therefore anything that resolves to a string that is acceptable input
format for the function's declared return type will produce a result.
+ Again, there is an exception for scalar bytea return values. In this
+ case, the R object being returned is first processed by the R
+ serialize command, and then the binary result is directly mapped
+ into a PostgreSQL bytea datum.
Similar to argument conversion, there is also a mapping between the
dimensionality of the declared PostgreSQL return type and the type of
R object. That mapping is shown in
@@ -596,6 +608,9 @@ SELECT row_number(), f1 from t;
the body of a PL/R procedure, or in support thereof:
</para>
+ <sect1 id="plr-spi-rsupport-funcs-normal">
+ <title>Normal Support</title>
+
<variablelist>
<varlistentry>
@@ -851,7 +866,7 @@ cursor_obj <- pg.spi.cursor_open('my_cursor',plan);
<programlisting>
plan <- pg.spi.prepare('SELECT * FROM pg_class');
cursor_obj <- pg.spi.cursor_open('my_cursor',plan);
-data <- pg.spi.cursor_forward(cursor_obj,TRUE,10);
+data <- pg.spi.cursor_fetch(cursor_obj,TRUE,as.integer(10));
</programlisting>
</para>
<para>
@@ -951,8 +966,73 @@ pg.spi.cursor_close(cursor_obj);
</para>
</listitem>
</varlistentry>
+ </variablelist>
+ </sect1>
+ <sect1 id="plr-spi-rsupport-funcs-compat">
+ <title>RPostgreSQL Compatibility Support</title>
+ <variablelist>
+ <varlistentry>
+ <listitem>
+ <para>
+ The following functions are intended to provide some level of compatibility between
+ PL/R and RPostgreSQL (PostgreSQL DBI package). This allows, for example, a function
+ to be first prototyped using an R client, and then easily moved to PL/R for
+ production use.
+ </para>
+ </listitem>
+
+ <term><function>dbDriver</function>
+ (<type>character</type> <replaceable>dvr_name</replaceable>)
+ </term>
+ <term><function>dbConnect</function>
+ (<type>DBIDriver</type> <replaceable>drv</replaceable>,
+ <type>character</type> <replaceable>user</replaceable>,
+ <type>character</type> <replaceable>password</replaceable>,
+ <type>character</type> <replaceable>host</replaceable>,
+ <type>character</type> <replaceable>dbname</replaceable>,
+ <type>character</type> <replaceable>port</replaceable>,
+ <type>character</type> <replaceable>tty</replaceable>,
+ <type>character</type> <replaceable>options</replaceable>)
+ </term>
+ <term><function>dbSendQuery</function>
+ (<type>DBIConnection</type> <replaceable>conn</replaceable>,
+ <type>character</type> <replaceable>sql</replaceable>)
+ </term>
+ <term><function>fetch</function>
+ (<type>DBIResult</type> <replaceable>rs</replaceable>,
+ <type>integer</type> <replaceable>num_rows</replaceable>)
+ </term>
+ <term><function>dbClearResult</function>
+ (<type>DBIResult</type> <replaceable>rs</replaceable>)
+ </term>
+ <term><function>dbGetQuery</function>
+ (<type>DBIConnection</type> <replaceable>conn</replaceable>,
+ <type>character</type> <replaceable>sql</replaceable>)
+ </term>
+ <term><function>dbReadTable</function>
+ (<type>DBIConnection</type> <replaceable>conn</replaceable>,
+ <type>character</type> <replaceable>name</replaceable>)
+ </term>
+ <term><function>dbDisconnect</function>
+ (<type>DBIConnection</type> <replaceable>conn</replaceable>)
+ </term>
+ <term><function>dbUnloadDriver</function>
+ (<type>DBIDriver</type> <replaceable>drv</replaceable>)
+ </term>
+
+ <listitem>
+ <para>
+ These functions nominally work like their RPostgreSQL counterparts
+ except that all queries are performed in the current database.
+ Therefore all driver and connection related parameters are
+ ignored, and dbDriver, dbConnect, dbDisconnect, and dbUnloadDriver
+ are no-ops.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
+ </sect1>
</chapter>
<chapter id="plr-pgsql-support-funcs">
@@ -1119,6 +1199,30 @@ select plr_array_accum('{23,35}', 42);
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><function>plr_set_display</function>(<type>text</type> <replaceable>display</replaceable>)</term>
+ <listitem>
+ <para>
+ Sets the DISPLAY environment vaiable under which the Postmaster is currently
+ running. This may be useful if using R to plot to a virtual frame buffer.
+ This function is installed with EXECUTE permission revoked from PUBLIC.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>plr_get_raw</function>(<type>bytea</type> <replaceable>serialized_object</replaceable>)</term>
+ <listitem>
+ <para>
+ By default, when R objects are returned as type <type>bytea</type>, the
+ R object is serialized using an internal R function prior to sending to PostgreSQL.
+ This function unserializes the R object using another internal R function, and
+ returns the pure raw bytes to PostgreSQL. This is useful, for example, if the R
+ object being returned is a JPEG or PNG graphic for use outside of R.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</chapter>
View
20 expected/plr.out
@@ -95,7 +95,7 @@ select reval('a <- sd(c(1,2,3)); b <- mean(c(1,2,3)); a + b');
create or replace function "commandArgs"() returns text[] as '' language 'plr';
select "commandArgs"();
- commandArgs
+ commandArgs
----------------------------------------
{PL/R,--silent,--no-save,--no-restore}
(1 row)
@@ -868,3 +868,21 @@ SELECT * FROM cursor_fetch_test_arg(3);
3
(3 rows)
+--Test bytea arguments and return values: serialize/unserialize
+create or replace function test_serialize(text)
+returns bytea as '
+ mydf <- pg.spi.exec(arg1)
+ return (mydf)
+' language 'plr';
+create or replace function restore_df(bytea)
+returns setof record as '
+ return (arg1)
+' language 'plr';
+select * from restore_df((select test_serialize('select oid, typname from pg_type where typname in (''oid'',''name'',''int4'')'))) as t(oid oid, typname name);
+ oid | typname
+-----+---------
+ 19 | name
+ 23 | int4
+ 26 | oid
+(3 rows)
+
View
2  pg_backend_support.c
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
View
158 pg_conversion.c
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
@@ -67,6 +67,8 @@ static Tuplestorestate *get_generic_tuplestore(SEXP rval,
MemoryContext per_query_ctx,
bool retset);
+extern char *last_R_error_msg;
+
/*
* given a scalar pg value, convert to a one row R vector
*/
@@ -74,20 +76,58 @@ SEXP
pg_scalar_get_r(Datum dvalue, Oid arg_typid, FmgrInfo arg_out_func)
{
SEXP result;
- char *value;
- value = DatumGetCString(FunctionCall3(&arg_out_func,
- dvalue,
- (Datum) 0,
- Int32GetDatum(-1)));
+ /* add our value to it */
+ if (arg_typid != BYTEAOID)
+ {
+ char *value;
- /* get new vector of the appropriate type, length 1 */
- PROTECT(result = get_r_vector(arg_typid, 1));
+ value = DatumGetCString(FunctionCall3(&arg_out_func,
+ dvalue,
+ (Datum) 0,
+ Int32GetDatum(-1)));
- /* add our value to it */
- pg_get_one_r(value, arg_typid, &result, 0);
+ /* get new vector of the appropriate type, length 1 */
+ PROTECT(result = get_r_vector(arg_typid, 1));
+ pg_get_one_r(value, arg_typid, &result, 0);
+ UNPROTECT(1);
+ }
+ else
+ {
+ SEXP s, t, obj;
+ int status;
- UNPROTECT(1);
+ PROTECT(obj = get_r_vector(arg_typid, VARSIZE((bytea *) dvalue)));
+ memcpy((char *) RAW(obj),
+ VARDATA((bytea *) dvalue),
+ VARSIZE((bytea *) dvalue));
+
+ /*
+ * Need to construct a call to
+ * unserialize(rval)
+ */
+ PROTECT(t = s = allocList(2));
+ SET_TYPEOF(s, LANGSXP);
+ SETCAR(t, install("unserialize")); t = CDR(t);
+ SETCAR(t, obj);
+
+ PROTECT(result = R_tryEval(s, R_GlobalEnv, &status));
+ if(status != 0)
+ {
+ if (last_R_error_msg)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("R interpreter expression evaluation error"),
+ errdetail("%s", last_R_error_msg)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("R interpreter expression evaluation error"),
+ errdetail("R expression evaluation error caught in \"unserialize\".")));
+ }
+
+ UNPROTECT(2);
+ }
return result;
}
@@ -370,6 +410,9 @@ get_r_vector(Oid typtype, int numels)
case BOOLOID:
PROTECT(result = NEW_LOGICAL(numels));
break;
+ case BYTEAOID:
+ PROTECT(result = NEW_RAW(numels));
+ break;
default:
/* Everything else is defaulted to string */
PROTECT(result = NEW_CHARACTER(numels));
@@ -449,7 +492,7 @@ r_get_pg(SEXP rval, plr_function *function, FunctionCallInfo fcinfo)
}
if (function->result_elem == 0)
- result = get_scalar_datum(rval, function->result_in_func, function->result_elem, &isnull);
+ result = get_scalar_datum(rval, function->result_typid, function->result_in_func, &isnull);
else
result = get_array_datum(rval, function, 0, &isnull);
@@ -718,38 +761,88 @@ get_tuplestore(SEXP rval, plr_function *function, FunctionCallInfo fcinfo, bool
}
Datum
-get_scalar_datum(SEXP rval, FmgrInfo result_in_func, Oid result_elem, bool *isnull)
+get_scalar_datum(SEXP rval, Oid result_typid, FmgrInfo result_in_func, bool *isnull)
{
Datum dvalue;
SEXP obj;
const char *value;
/*
- * if the element type is zero, we don't have an array,
- * so coerce to string and take the first element as a scalar
+ * Element type is zero, we don't have an array, so coerce to string
+ * and take the first element as a scalar
+ *
+ * Exception: if result type is BYTEA, we want to return the whole
+ * object in serialized form
*/
- PROTECT(obj = AS_CHARACTER(rval));
- value = CHAR(STRING_ELT(obj, 0));
-
- if (STRING_ELT(obj, 0) == NA_STRING)
- {
- *isnull = true;
- dvalue = (Datum) 0;
- }
- else if (value != NULL)
+ if (result_typid != BYTEAOID)
{
- dvalue = FunctionCall3(&result_in_func,
- CStringGetDatum(value),
- ObjectIdGetDatum(result_elem),
- Int32GetDatum(-1));
+ PROTECT(obj = AS_CHARACTER(rval));
+ if (STRING_ELT(obj, 0) == NA_STRING)
+ {
+ UNPROTECT(1);
+ *isnull = true;
+ dvalue = (Datum) 0;
+ return dvalue;
+ }
+ value = CHAR(STRING_ELT(obj, 0));
+ UNPROTECT(1);
+
+ if (value != NULL)
+ {
+ dvalue = FunctionCall3(&result_in_func,
+ CStringGetDatum(value),
+ ObjectIdGetDatum(0),
+ Int32GetDatum(-1));
+ }
+ else
+ {
+ *isnull = true;
+ dvalue = (Datum) 0;
+ }
}
else
{
- *isnull = true;
- dvalue = (Datum) 0;
- }
+ SEXP s, t;
+ int len, rsize, status;
+ bytea *result;
+ char *rptr;
- UNPROTECT(1);
+ /*
+ * Need to construct a call to
+ * serialize(rval, NULL)
+ */
+ PROTECT(t = s = allocList(3));
+ SET_TYPEOF(s, LANGSXP);
+ SETCAR(t, install("serialize")); t = CDR(t);
+ SETCAR(t, rval); t = CDR(t);
+ SETCAR(t, R_NilValue);
+
+ PROTECT(obj = R_tryEval(s, R_GlobalEnv, &status));
+ if(status != 0)
+ {
+ if (last_R_error_msg)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("R interpreter expression evaluation error"),
+ errdetail("%s", last_R_error_msg)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("R interpreter expression evaluation error"),
+ errdetail("R expression evaluation error caught in \"serialize\".")));
+ }
+ len = LENGTH(obj);
+
+ rsize = VARHDRSZ + len;
+ result = (bytea *) palloc(rsize);
+ SET_VARSIZE(result, rsize);
+ rptr = VARDATA(result);
+ memcpy(rptr, (char *) RAW(obj), rsize - VARHDRSZ);
+
+ UNPROTECT(2);
+
+ dvalue = PointerGetDatum(result);
+ }
return dvalue;
}
@@ -1414,4 +1507,3 @@ get_generic_tuplestore(SEXP rval,
return tupstore;
}
-
View
11 pg_rsupport.c
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
@@ -455,7 +455,7 @@ plr_SPI_execp(SEXP rsaved_plan, SEXP rargvalues)
saved_plan_desc *plan_desc = (saved_plan_desc *) R_ExternalPtrAddr(rsaved_plan);
void *saved_plan = plan_desc->saved_plan;
int nargs = plan_desc->nargs;
- Oid *typelems = plan_desc->typelems;
+ Oid *typeids = plan_desc->typeids;
FmgrInfo *typinfuncs = plan_desc->typinfuncs;
int i;
Datum *argvalues = NULL;
@@ -492,7 +492,7 @@ plr_SPI_execp(SEXP rsaved_plan, SEXP rargvalues)
{
PROTECT(obj = VECTOR_ELT(rargvalues, i));
- argvalues[i] = get_scalar_datum(obj, typinfuncs[i], typelems[i], &isnull);
+ argvalues[i] = get_scalar_datum(obj, typeids[i], typinfuncs[i], &isnull);
if (!isnull)
nulls[i] = ' ';
else
@@ -615,7 +615,7 @@ plr_SPI_cursor_open(SEXP cursor_name_arg,SEXP rsaved_plan, SEXP rargvalues)
saved_plan_desc *plan_desc = (saved_plan_desc *) R_ExternalPtrAddr(rsaved_plan);
void *saved_plan = plan_desc->saved_plan;
int nargs = plan_desc->nargs;
- Oid *typelems = plan_desc->typelems;
+ Oid *typeids = plan_desc->typeids;
FmgrInfo *typinfuncs = plan_desc->typinfuncs;
int i;
Datum *argvalues = NULL;
@@ -649,7 +649,7 @@ plr_SPI_cursor_open(SEXP cursor_name_arg,SEXP rsaved_plan, SEXP rargvalues)
{
PROTECT(obj = VECTOR_ELT(rargvalues, i));
- argvalues[i] = get_scalar_datum(obj, typinfuncs[i], typelems[i], &isnull);
+ argvalues[i] = get_scalar_datum(obj, typeids[i], typinfuncs[i], &isnull);
if (!isnull)
nulls[i] = ' ';
else
@@ -819,3 +819,4 @@ rsupport_error_callback(void *arg)
if (arg)
errcontext("In R support function %s", (char *) arg);
}
+
View
90 pg_userfuncs.c
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
@@ -407,3 +407,91 @@ plr_unset_rhome(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(PG_STR_GET_TEXT("OK"));
}
+
+/*-----------------------------------------------------------------------------
+ * plr_set_display :
+ * utility function to set the DISPLAY environment variable under
+ * which the postmaster is running.
+ *----------------------------------------------------------------------------
+ */
+PG_FUNCTION_INFO_V1(plr_set_display);
+Datum
+plr_set_display(PG_FUNCTION_ARGS)
+{
+ char *display = PG_TEXT_GET_STR(PG_GETARG_TEXT_P(0));
+ size_t d_len = strlen(display);
+
+ if (d_len)
+ {
+ char *denv;
+ MemoryContext oldcontext;
+
+ /* Needs to live until/unless we explicitly delete it */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ denv = palloc(9 + d_len);
+ MemoryContextSwitchTo(oldcontext);
+
+ sprintf(denv, "DISPLAY=%s", display);
+ putenv(denv);
+ }
+
+ PG_RETURN_TEXT_P(PG_STR_GET_TEXT("OK"));
+}
+
+/*-----------------------------------------------------------------------------
+ * plr_get_raw :
+ * utility function to ...
+ *----------------------------------------------------------------------------
+ */
+extern char *last_R_error_msg;
+
+PG_FUNCTION_INFO_V1(plr_get_raw);
+Datum
+plr_get_raw(PG_FUNCTION_ARGS)
+{
+ SEXP result;
+ SEXP s, t, obj;
+ int status;
+ bytea *bvalue = PG_GETARG_BYTEA_P(0);
+ int len, rsize;
+ bytea *bresult;
+ char *brptr;
+
+ PROTECT(obj = NEW_RAW(VARSIZE(bvalue)));
+ memcpy((char *) RAW(obj), VARDATA(bvalue), VARSIZE(bvalue));
+
+ /*
+ * Need to construct a call to
+ * unserialize(rval)
+ */
+ PROTECT(t = s = allocList(2));
+ SET_TYPEOF(s, LANGSXP);
+ SETCAR(t, install("unserialize")); t = CDR(t);
+ SETCAR(t, obj);
+
+ PROTECT(result = R_tryEval(s, R_GlobalEnv, &status));
+ if(status != 0)
+ {
+ if (last_R_error_msg)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("R interpreter expression evaluation error"),
+ errdetail("%s", last_R_error_msg)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("R interpreter expression evaluation error"),
+ errdetail("R expression evaluation error caught in \"unserialize\".")));
+ }
+
+ len = LENGTH(result);
+ rsize = VARHDRSZ + len;
+ bresult = (bytea *) palloc(rsize);
+ SET_VARSIZE(bresult, rsize);
+ brptr = VARDATA(bresult);
+ memcpy(brptr, (char *) RAW(result), rsize - VARHDRSZ);
+
+ UNPROTECT(2);
+
+ PG_RETURN_BYTEA_P(bresult);
+}
View
48 plr.c
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
@@ -107,6 +107,43 @@ static Oid plr_nspOid = InvalidOid;
#define SPI_LASTOID_CMD \
"pg.spi.lastoid <-function() " \
"{.Call(\"plr_SPI_lastoid\")}"
+#define SPI_DBDRIVER_CMD \
+ "dbDriver <-function(db_name)\n" \
+ "{return(NA)}"
+#define SPI_DBCONN_CMD \
+ "dbConnect <- function(drv,user=\"\",password=\"\",host=\"\",dbname=\"\",port=\"\",tty =\"\",options=\"\")\n" \
+ "{return(NA)}"
+#define SPI_DBSENDQUERY_CMD \
+ "dbSendQuery <- function(conn, sql) {\n" \
+ "plan <- pg.spi.prepare(sql)\n" \
+ "cursor_obj <- pg.spi.cursor_open(\"plr_cursor\",plan)\n" \
+ "return(cursor_obj)\n" \
+ "}"
+#define SPI_DBFETCH_CMD \
+ "fetch <- function(rs,n) {\n" \
+ "data <- pg.spi.cursor_fetch(rs, TRUE, as.integer(n))\n" \
+ "return(data)\n" \
+ "}"
+#define SPI_DBCLEARRESULT_CMD \
+ "dbClearResult <- function(rs) {\n" \
+ "pg.spi.cursor_close(rs)\n" \
+ "}"
+#define SPI_DBGETQUERY_CMD \
+ "dbGetQuery <-function(conn, sql) {\n" \
+ "data <- pg.spi.exec(sql)\n" \
+ "return(data)\n" \
+ "}"
+#define SPI_DBREADTABLE_CMD \
+ "dbReadTable <- function(con, name, row.names = \"row_names\", check.names = TRUE) {\n" \
+ "data <- dbGetQuery(con, paste(\"SELECT * from\", name))\n" \
+ "return(data)\n" \
+ "}"
+#define SPI_DBDISCONN_CMD \
+ "dbDisconnect <- function(con)\n" \
+ "{return(NA)}"
+#define SPI_DBUNLOADDRIVER_CMD \
+ "dbUnloadDriver <-function(drv)\n" \
+ "{return(NA)}"
#define SPI_FACTOR_CMD \
"pg.spi.factor <- function(arg1) {\n" \
" for (col in 1:ncol(arg1)) {\n" \
@@ -405,6 +442,15 @@ plr_load_builtins(Oid funcid)
SPI_CURSOR_MOVE_CMD,
SPI_CURSOR_CLOSE_CMD,
SPI_LASTOID_CMD,
+ SPI_DBDRIVER_CMD,
+ SPI_DBCONN_CMD,
+ SPI_DBSENDQUERY_CMD,
+ SPI_DBFETCH_CMD,
+ SPI_DBCLEARRESULT_CMD,
+ SPI_DBGETQUERY_CMD,
+ SPI_DBREADTABLE_CMD,
+ SPI_DBDISCONN_CMD,
+ SPI_DBUNLOADDRIVER_CMD,
SPI_FACTOR_CMD,
/* handy predefined R functions */
View
8 plr.h
@@ -2,7 +2,7 @@
* PL/R - PostgreSQL support for R as a
* procedural language (PL)
*
- * Copyright (c) 2003-2007 by Joseph E. Conway
+ * Copyright (c) 2003-2009 by Joseph E. Conway
* ALL RIGHTS RESERVED
*
* Joe Conway <mail@joeconway.com>
@@ -58,7 +58,7 @@
#endif
#include "Rinternals.h"
#include "Rdefines.h"
-#if (R_VERSION < 133120) /* R_VERSION >= 2.8.0 */
+#if (R_VERSION < 133120) /* R_VERSION < 2.8.0 */
#include "Rdevices.h"
#endif
@@ -452,7 +452,7 @@ extern SEXP pg_scalar_get_r(Datum dvalue, Oid arg_typid, FmgrInfo arg_out_func);
extern SEXP pg_array_get_r(Datum dvalue, FmgrInfo out_func, int typlen, bool typbyval, char typalign);
extern SEXP pg_tuple_get_r_frame(int ntuples, HeapTuple *tuples, TupleDesc tupdesc);
extern Datum r_get_pg(SEXP rval, plr_function *function, FunctionCallInfo fcinfo);
-extern Datum get_scalar_datum(SEXP rval, FmgrInfo result_in_func, Oid result_elem, bool *isnull);
+extern Datum get_scalar_datum(SEXP rval, Oid result_typ, FmgrInfo result_in_func, bool *isnull);
/* Postgres support functions installed into the R interpreter */
extern void throw_pg_notice(const char **msg);
@@ -477,6 +477,8 @@ extern Datum plr_array_accum(PG_FUNCTION_ARGS);
extern Datum plr_environ(PG_FUNCTION_ARGS);
extern Datum plr_set_rhome(PG_FUNCTION_ARGS);
extern Datum plr_unset_rhome(PG_FUNCTION_ARGS);
+extern Datum plr_set_display(PG_FUNCTION_ARGS);
+extern Datum plr_get_raw(PG_FUNCTION_ARGS);
/* Postgres backend support functions */
extern void compute_function_hashkey(FunctionCallInfo fcinfo,
View
12 plr.sql.in
@@ -81,3 +81,15 @@ RETURNS text
AS 'MODULE_PATHNAME','plr_unset_rhome'
LANGUAGE 'C';
REVOKE EXECUTE ON FUNCTION plr_unset_rhome () FROM PUBLIC;
+
+CREATE OR REPLACE FUNCTION plr_set_display (text)
+RETURNS text
+AS 'MODULE_PATHNAME','plr_set_display'
+LANGUAGE 'C' WITH (isstrict);
+REVOKE EXECUTE ON FUNCTION plr_set_display (text) FROM PUBLIC;
+
+CREATE OR REPLACE FUNCTION plr_get_raw (bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME','plr_get_raw'
+LANGUAGE 'C' WITH (isstrict);
+
View
13 sql/plr.sql
@@ -372,3 +372,16 @@ SELECT * FROM cursor_direction_test();
CREATE OR REPLACE FUNCTION cursor_fetch_test_arg(integer) RETURNS SETOF integer AS 'plan<-pg.spi.prepare("SELECT * FROM generate_series(1,$1)",c(INT4OID)); cursor<-pg.spi.cursor_open("curs",plan,list(arg1)); dat<-pg.spi.cursor_fetch(cursor,TRUE,arg1); pg.spi.cursor_close(cursor); return (dat);' language 'plr';
SELECT * FROM cursor_fetch_test_arg(3);
+--Test bytea arguments and return values: serialize/unserialize
+create or replace function test_serialize(text)
+returns bytea as '
+ mydf <- pg.spi.exec(arg1)
+ return (mydf)
+' language 'plr';
+
+create or replace function restore_df(bytea)
+returns setof record as '
+ return (arg1)
+' language 'plr';
+
+select * from restore_df((select test_serialize('select oid, typname from pg_type where typname in (''oid'',''name'',''int4'')'))) as t(oid oid, typname name);
Please sign in to comment.
Something went wrong with that request. Please try again.