aboutsummaryrefslogtreecommitdiff
path: root/src/pl/plpython/plpython.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/plpython/plpython.c')
-rw-r--r--src/pl/plpython/plpython.c3868
1 files changed, 1989 insertions, 1879 deletions
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index edb2d69a9fe..3483d21ae33 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.9 2001/10/22 19:32:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.10 2001/10/25 05:50:20 momjian Exp $
*
*********************************************************************
*/
@@ -70,88 +70,100 @@
typedef PyObject *(*PLyDatumToObFunc) (const char *);
-typedef struct PLyDatumToOb {
- PLyDatumToObFunc func;
- FmgrInfo typfunc;
- Oid typelem;
- bool typbyval;
-} PLyDatumToOb;
+typedef struct PLyDatumToOb
+{
+ PLyDatumToObFunc func;
+ FmgrInfo typfunc;
+ Oid typelem;
+ bool typbyval;
+} PLyDatumToOb;
-typedef struct PLyTupleToOb {
- PLyDatumToOb *atts;
- int natts;
-} PLyTupleToOb;
+typedef struct PLyTupleToOb
+{
+ PLyDatumToOb *atts;
+ int natts;
+} PLyTupleToOb;
-typedef union PLyTypeInput {
- PLyDatumToOb d;
- PLyTupleToOb r;
-} PLyTypeInput;
+typedef union PLyTypeInput
+{
+ PLyDatumToOb d;
+ PLyTupleToOb r;
+} PLyTypeInput;
/* convert PyObject to a Postgresql Datum or tuple.
* output from Python
*/
-typedef struct PLyObToDatum {
- FmgrInfo typfunc;
- Oid typelem;
- bool typbyval;
-} PLyObToDatum;
-
-typedef struct PLyObToTuple {
- PLyObToDatum *atts;
- int natts;
-} PLyObToTuple;
-
-typedef union PLyTypeOutput {
- PLyObToDatum d;
- PLyObToTuple r;
-} PLyTypeOutput;
+typedef struct PLyObToDatum
+{
+ FmgrInfo typfunc;
+ Oid typelem;
+ bool typbyval;
+} PLyObToDatum;
+
+typedef struct PLyObToTuple
+{
+ PLyObToDatum *atts;
+ int natts;
+} PLyObToTuple;
+
+typedef union PLyTypeOutput
+{
+ PLyObToDatum d;
+ PLyObToTuple r;
+} PLyTypeOutput;
/* all we need to move Postgresql data to Python objects,
* and vis versa
*/
-typedef struct PLyTypeInfo {
- PLyTypeInput in;
- PLyTypeOutput out;
- int is_rel;
-} PLyTypeInfo;
+typedef struct PLyTypeInfo
+{
+ PLyTypeInput in;
+ PLyTypeOutput out;
+ int is_rel;
+} PLyTypeInfo;
/* cached procedure data
*/
-typedef struct PLyProcedure {
- char *proname;
- TransactionId fn_xmin;
- CommandId fn_cmin;
- PLyTypeInfo result; /* also used to store info for trigger tuple type */
- PLyTypeInfo args[FUNC_MAX_ARGS];
- int nargs;
- PyObject *interp; /* restricted interpreter instance */
- PyObject *reval; /* interpreter return */
- PyObject *code; /* compiled procedure code */
- PyObject *statics; /* data saved across calls, local scope */
- PyObject *globals; /* data saved across calls, global score */
- PyObject *me; /* PyCObject containing pointer to this PLyProcedure */
-} PLyProcedure;
-
-
-/* Python objects.
+typedef struct PLyProcedure
+{
+ char *proname;
+ TransactionId fn_xmin;
+ CommandId fn_cmin;
+ PLyTypeInfo result; /* also used to store info for trigger
+ * tuple type */
+ PLyTypeInfo args[FUNC_MAX_ARGS];
+ int nargs;
+ PyObject *interp; /* restricted interpreter instance */
+ PyObject *reval; /* interpreter return */
+ PyObject *code; /* compiled procedure code */
+ PyObject *statics; /* data saved across calls, local scope */
+ PyObject *globals; /* data saved across calls, global score */
+ PyObject *me; /* PyCObject containing pointer to this
+ * PLyProcedure */
+} PLyProcedure;
+
+
+/* Python objects.
*/
-typedef struct PLyPlanObject {
- PyObject_HEAD;
- void *plan; /* return of an SPI_saveplan */
- int nargs;
- Oid *types;
- Datum *values;
- PLyTypeInfo *args;
-} PLyPlanObject;
-
-typedef struct PLyResultObject {
- PyObject_HEAD;
- /* HeapTuple *tuples; */
- PyObject *nrows; /* number of rows returned by query */
- PyObject *rows; /* data rows, or None if no data returned */
- PyObject *status; /* query status, SPI_OK_*, or SPI_ERR_* */
-} PLyResultObject;
+typedef struct PLyPlanObject
+{
+ PyObject_HEAD;
+ void *plan; /* return of an SPI_saveplan */
+ int nargs;
+ Oid *types;
+ Datum *values;
+ PLyTypeInfo *args;
+} PLyPlanObject;
+
+typedef struct PLyResultObject
+{
+ PyObject_HEAD;
+ /* HeapTuple *tuples; */
+ PyObject *nrows; /* number of rows returned by query */
+ PyObject *rows; /* data rows, or None if no data returned */
+ PyObject *status; /* query status, SPI_OK_*, or SPI_ERR_* */
+} PLyResultObject;
/* function declarations
@@ -160,7 +172,8 @@ typedef struct PLyResultObject {
/* the only exported function, with the magic telling Postgresql
* what function call interface it implements.
*/
-Datum plpython_call_handler(PG_FUNCTION_ARGS);
+Datum plpython_call_handler(PG_FUNCTION_ARGS);
+
PG_FUNCTION_INFO_V1(plpython_call_handler);
/* most of the remaining of the declarations, all static
@@ -178,12 +191,13 @@ static void PLy_init_plpy(void);
/* error handler. collects the current Python exception, if any,
* and appends it to the error and sends it to elog
*/
-static void PLy_elog(int, const char *, ...);
+static void PLy_elog(int, const char *,...);
/* call PyErr_SetString with a vprint interface
*/
-static void PLy_exception_set(PyObject *, const char *, ...)
- __attribute__ ((format (printf, 2, 3)));
+static void
+PLy_exception_set(PyObject *, const char *,...)
+__attribute__((format(printf, 2, 3)));
/* some utility functions
*/
@@ -198,9 +212,9 @@ static HeapTuple PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure *);
static PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *);
static PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *,
- HeapTuple *);
+ HeapTuple *);
static HeapTuple PLy_modify_tuple(PLyProcedure *, PyObject *,
- TriggerData *, HeapTuple);
+ TriggerData *, HeapTuple);
static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
@@ -210,8 +224,8 @@ static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, bool);
static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
- bool is_trigger,
- HeapTuple procTup, char *key);
+ bool is_trigger,
+ HeapTuple procTup, char *key);
static void PLy_procedure_compile(PLyProcedure *, const char *);
static char *PLy_procedure_munge_source(const char *, const char *);
@@ -238,7 +252,7 @@ static PyObject *PLyString_FromString(const char *);
/* global data
*/
-static int PLy_first_call = 1;
+static int PLy_first_call = 1;
static volatile int PLy_call_level = 0;
/* this gets modified in plpython_call_handler and PLy_elog.
@@ -253,42 +267,42 @@ static PyObject *PLy_interp_safe_globals = NULL;
static PyObject *PLy_importable_modules = NULL;
static PyObject *PLy_procedure_cache = NULL;
-char *PLy_importable_modules_list[] = {
- "array",
- "bisect",
- "calendar",
- "cmath",
- "errno",
- "marshal",
- "math",
- "md5",
- "mpz",
- "operator",
- "pickle",
- "random",
- "re",
- "sha",
- "string",
- "StringIO",
- "time",
- "whrandom",
- "zlib"
+char *PLy_importable_modules_list[] = {
+ "array",
+ "bisect",
+ "calendar",
+ "cmath",
+ "errno",
+ "marshal",
+ "math",
+ "md5",
+ "mpz",
+ "operator",
+ "pickle",
+ "random",
+ "re",
+ "sha",
+ "string",
+ "StringIO",
+ "time",
+ "whrandom",
+ "zlib"
};
/* Python exceptions
*/
-PyObject *PLy_exc_error = NULL;
-PyObject *PLy_exc_fatal = NULL;
-PyObject *PLy_exc_spi_error = NULL;
+PyObject *PLy_exc_error = NULL;
+PyObject *PLy_exc_fatal = NULL;
+PyObject *PLy_exc_spi_error = NULL;
/* some globals for the python module
*/
static char PLy_plan_doc[] = {
- "Store a PostgreSQL plan"
+ "Store a PostgreSQL plan"
};
static char PLy_result_doc[] = {
- "Results of a PostgreSQL query"
+ "Results of a PostgreSQL query"
};
@@ -324,58 +338,62 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
Datum
plpython_call_handler(PG_FUNCTION_ARGS)
{
- DECLARE_EXC();
- Datum retval;
- bool is_trigger;
- PLyProcedure *volatile proc = NULL;
+ DECLARE_EXC();
+ Datum retval;
+ bool is_trigger;
+ PLyProcedure *volatile proc = NULL;
- enter();
+ enter();
- if (PLy_first_call)
- PLy_init_all();
+ if (PLy_first_call)
+ PLy_init_all();
- if (SPI_connect() != SPI_OK_CONNECT)
- elog(ERROR, "plpython: Unable to connect to SPI manager");
+ if (SPI_connect() != SPI_OK_CONNECT)
+ elog(ERROR, "plpython: Unable to connect to SPI manager");
- CALL_LEVEL_INC();
- is_trigger = CALLED_AS_TRIGGER(fcinfo);
+ CALL_LEVEL_INC();
+ is_trigger = CALLED_AS_TRIGGER(fcinfo);
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
- CALL_LEVEL_DEC();
- if (PLy_call_level == 0)
+ SAVE_EXC();
+ if (TRAP_EXC())
{
- PLy_restart_in_progress = 0;
- PyErr_Clear();
+ RESTORE_EXC();
+ CALL_LEVEL_DEC();
+ if (PLy_call_level == 0)
+ {
+ PLy_restart_in_progress = 0;
+ PyErr_Clear();
+ }
+ else
+ PLy_restart_in_progress += 1;
+ if (proc)
+ Py_DECREF(proc->me);
+ RERAISE_EXC();
}
- else
- PLy_restart_in_progress += 1;
- if (proc)
- { Py_DECREF(proc->me); }
- RERAISE_EXC();
- }
- /*elog(NOTICE, "PLy_restart_in_progress is %d", PLy_restart_in_progress);*/
+ /*
+ * elog(NOTICE, "PLy_restart_in_progress is %d",
+ * PLy_restart_in_progress);
+ */
+
+ proc = PLy_procedure_get(fcinfo, is_trigger);
- proc = PLy_procedure_get(fcinfo, is_trigger);
+ if (is_trigger)
+ {
+ HeapTuple trv = PLy_trigger_handler(fcinfo, proc);
+
+ retval = PointerGetDatum(trv);
+ }
+ else
+ retval = PLy_function_handler(fcinfo, proc);
- if (is_trigger)
- {
- HeapTuple trv = PLy_trigger_handler(fcinfo, proc);
- retval = PointerGetDatum(trv);
- }
- else
- retval = PLy_function_handler(fcinfo, proc);
+ CALL_LEVEL_DEC();
+ RESTORE_EXC();
- CALL_LEVEL_DEC();
- RESTORE_EXC();
-
- Py_DECREF(proc->me);
- refc(proc->me);
+ Py_DECREF(proc->me);
+ refc(proc->me);
- return retval;
+ return retval;
}
/* trigger and function sub handlers
@@ -389,339 +407,355 @@ plpython_call_handler(PG_FUNCTION_ARGS)
* to take no arguments and return an argument of type opaque.
*/
HeapTuple
-PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
+PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
{
- DECLARE_EXC();
- HeapTuple rv = NULL;
- PyObject * volatile plargs = NULL;
- PyObject * volatile plrv = NULL;
+ DECLARE_EXC();
+ HeapTuple rv = NULL;
+ PyObject *volatile plargs = NULL;
+ PyObject *volatile plrv = NULL;
- enter();
+ enter();
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
- Py_XDECREF(plargs);
- Py_XDECREF(plrv);
+ Py_XDECREF(plargs);
+ Py_XDECREF(plrv);
- RERAISE_EXC();
- }
+ RERAISE_EXC();
+ }
- plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
- plrv = PLy_procedure_call(proc, "TD", plargs);
+ plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
+ plrv = PLy_procedure_call(proc, "TD", plargs);
- /* Disconnect from SPI manager
- */
- if (SPI_finish() != SPI_OK_FINISH)
- elog(ERROR, "plpython: SPI_finish failed");
+ /*
+ * Disconnect from SPI manager
+ */
+ if (SPI_finish() != SPI_OK_FINISH)
+ elog(ERROR, "plpython: SPI_finish failed");
- if (plrv == NULL)
- elog(FATAL, "Aiieee, PLy_procedure_call returned NULL");
+ if (plrv == NULL)
+ elog(FATAL, "Aiieee, PLy_procedure_call returned NULL");
- if (PLy_restart_in_progress)
- elog(FATAL, "Aiieee, restart in progress not expected");
+ if (PLy_restart_in_progress)
+ elog(FATAL, "Aiieee, restart in progress not expected");
- /* return of None means we're happy with the tuple
- */
- if (plrv != Py_None)
- {
- char *srv;
+ /*
+ * return of None means we're happy with the tuple
+ */
+ if (plrv != Py_None)
+ {
+ char *srv;
- if (!PyString_Check(plrv))
- elog(ERROR, "plpython: Expected trigger to return None or a String");
+ if (!PyString_Check(plrv))
+ elog(ERROR, "plpython: Expected trigger to return None or a String");
- srv = PyString_AsString(plrv);
- if (strcasecmp(srv, "SKIP") == 0)
- rv = NULL;
- else if (strcasecmp(srv, "MODIFY") == 0)
- {
- TriggerData *tdata = (TriggerData *) fcinfo->context;
+ srv = PyString_AsString(plrv);
+ if (strcasecmp(srv, "SKIP") == 0)
+ rv = NULL;
+ else if (strcasecmp(srv, "MODIFY") == 0)
+ {
+ TriggerData *tdata = (TriggerData *) fcinfo->context;
- if ((TRIGGER_FIRED_BY_INSERT(tdata->tg_event)) ||
- (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)))
- {
- rv = PLy_modify_tuple(proc, plargs, tdata, rv);
- }
- else
- elog(NOTICE,"plpython: Ignoring modified tuple in DELETE trigger");
- }
- else if (strcasecmp(srv, "OK"))
- {
- /* hmmm, perhaps they only read the pltcl page, not a surprising
- * thing since i've written no documentation, so accept a
- * belated OK
- */
- elog(ERROR, "plpython: Expected return to be 'SKIP' or 'MODIFY'");
+ if ((TRIGGER_FIRED_BY_INSERT(tdata->tg_event)) ||
+ (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)))
+ rv = PLy_modify_tuple(proc, plargs, tdata, rv);
+ else
+ elog(NOTICE, "plpython: Ignoring modified tuple in DELETE trigger");
+ }
+ else if (strcasecmp(srv, "OK"))
+ {
+ /*
+ * hmmm, perhaps they only read the pltcl page, not a
+ * surprising thing since i've written no documentation, so
+ * accept a belated OK
+ */
+ elog(ERROR, "plpython: Expected return to be 'SKIP' or 'MODIFY'");
+ }
}
- }
- Py_DECREF(plargs);
- Py_DECREF(plrv);
+ Py_DECREF(plargs);
+ Py_DECREF(plrv);
- RESTORE_EXC();
+ RESTORE_EXC();
- return rv;
+ return rv;
}
HeapTuple
-PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
- HeapTuple otup)
-{
- DECLARE_EXC();
- PyObject * volatile plntup;
- PyObject * volatile plkeys;
- PyObject * volatile platt;
- PyObject * volatile plval;
- PyObject * volatile plstr;
- HeapTuple rtup;
- int natts, i, j, attn, atti;
- int * volatile modattrs;
- Datum * volatile modvalues;
- char *volatile modnulls;
- TupleDesc tupdesc;
-
- plntup = plkeys = platt = plval = plstr = NULL;
- modattrs = NULL;
- modvalues = NULL;
- modnulls = NULL;
-
- enter();
-
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
-
- Py_XDECREF(plntup);
- Py_XDECREF(plkeys);
- Py_XDECREF(platt);
- Py_XDECREF(plval);
- Py_XDECREF(plstr);
-
- if (modnulls)
- pfree(modnulls);
- if (modvalues)
- pfree(modvalues);
- if (modattrs)
+PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
+ HeapTuple otup)
+{
+ DECLARE_EXC();
+ PyObject *volatile plntup;
+ PyObject *volatile plkeys;
+ PyObject *volatile platt;
+ PyObject *volatile plval;
+ PyObject *volatile plstr;
+ HeapTuple rtup;
+ int natts,
+ i,
+ j,
+ attn,
+ atti;
+ int *volatile modattrs;
+ Datum *volatile modvalues;
+ char *volatile modnulls;
+ TupleDesc tupdesc;
+
+ plntup = plkeys = platt = plval = plstr = NULL;
+ modattrs = NULL;
+ modvalues = NULL;
+ modnulls = NULL;
+
+ enter();
+
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+
+ Py_XDECREF(plntup);
+ Py_XDECREF(plkeys);
+ Py_XDECREF(platt);
+ Py_XDECREF(plval);
+ Py_XDECREF(plstr);
+
+ if (modnulls)
+ pfree(modnulls);
+ if (modvalues)
+ pfree(modvalues);
+ if (modattrs)
+ pfree(modattrs);
+
+ RERAISE_EXC();
+ }
+
+ if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
+ elog(ERROR, "plpython: TD[\"new\"] deleted, unable to modify tuple");
+ if (!PyDict_Check(plntup))
+ elog(ERROR, "plpython: TD[\"new\"] is not a dictionary object");
+ Py_INCREF(plntup);
+
+ plkeys = PyDict_Keys(plntup);
+ natts = PyList_Size(plkeys);
+
+ if (natts != proc->result.out.r.natts)
+ elog(ERROR, "plpython: TD[\"new\"] has an incorrect number of keys.");
+
+ modattrs = palloc(natts * sizeof(int));
+ modvalues = palloc(natts * sizeof(Datum));
+ for (i = 0; i < natts; i++)
+ {
+ modattrs[i] = i + 1;
+ modvalues[i] = (Datum) NULL;
+ }
+ modnulls = palloc(natts + 1);
+ memset(modnulls, 'n', natts);
+ modnulls[natts] = '\0';
+
+ tupdesc = tdata->tg_relation->rd_att;
+
+ for (j = 0; j < natts; j++)
+ {
+ char *src;
+
+ platt = PyList_GetItem(plkeys, j);
+ if (!PyString_Check(platt))
+ elog(ERROR, "plpython: attribute is not a string");
+ attn = modattrs[j] = SPI_fnumber(tupdesc, PyString_AsString(platt));
+
+ if (attn == SPI_ERROR_NOATTRIBUTE)
+ elog(ERROR, "plpython: invalid attribute `%s' in tuple.",
+ PyString_AsString(platt));
+ atti = attn - 1;
+
+ plval = PyDict_GetItem(plntup, platt);
+ if (plval == NULL)
+ elog(FATAL, "plpython: interpreter is probably corrupted");
+
+ Py_INCREF(plval);
+
+ if (plval != Py_None)
+ {
+ plstr = PyObject_Str(plval);
+ src = PyString_AsString(plstr);
+
+ modvalues[j] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
+ CStringGetDatum(src),
+ ObjectIdGetDatum(proc->result.out.r.atts[atti].typelem),
+ Int32GetDatum(tupdesc->attrs[j]->atttypmod));
+ modnulls[j] = ' ';
+
+ Py_DECREF(plstr);
+ plstr = NULL;
+ }
+ Py_DECREF(plval);
+ plval = NULL;
+
+ }
+ rtup = SPI_modifytuple(tdata->tg_relation, otup, natts, modattrs,
+ modvalues, modnulls);
+
+ /*
+ * FIXME -- these leak if not explicity pfree'd by other elog calls,
+ * no?
+ */
pfree(modattrs);
+ pfree(modvalues);
+ pfree(modnulls);
+
+ if (rtup == NULL)
+ elog(ERROR, "plpython: SPI_modifytuple failed -- error %d", SPI_result);
+
+ Py_DECREF(plntup);
+ Py_DECREF(plkeys);
+
+ RESTORE_EXC();
- RERAISE_EXC();
- }
-
- if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
- elog(ERROR, "plpython: TD[\"new\"] deleted, unable to modify tuple");
- if (!PyDict_Check(plntup))
- elog(ERROR, "plpython: TD[\"new\"] is not a dictionary object");
- Py_INCREF(plntup);
-
- plkeys = PyDict_Keys(plntup);
- natts = PyList_Size(plkeys);
-
- if (natts != proc->result.out.r.natts)
- elog(ERROR, "plpython: TD[\"new\"] has an incorrect number of keys.");
-
- modattrs = palloc(natts * sizeof(int));
- modvalues = palloc(natts * sizeof(Datum));
- for (i = 0; i < natts; i++)
- {
- modattrs[i] = i + 1;
- modvalues[i] = (Datum) NULL;
- }
- modnulls = palloc(natts + 1);
- memset(modnulls, 'n', natts);
- modnulls[natts] = '\0';
-
- tupdesc = tdata->tg_relation->rd_att;
-
- for (j = 0; j < natts; j++)
- {
- char *src;
-
- platt = PyList_GetItem(plkeys, j);
- if (!PyString_Check(platt))
- elog(ERROR, "plpython: attribute is not a string");
- attn = modattrs[j] = SPI_fnumber(tupdesc, PyString_AsString(platt));
-
- if (attn == SPI_ERROR_NOATTRIBUTE)
- elog(ERROR, "plpython: invalid attribute `%s' in tuple.",
- PyString_AsString(platt));
- atti = attn - 1;
-
- plval = PyDict_GetItem(plntup, platt);
- if (plval == NULL)
- elog(FATAL, "plpython: interpreter is probably corrupted");
-
- Py_INCREF(plval);
-
- if (plval != Py_None)
- {
- plstr = PyObject_Str(plval);
- src = PyString_AsString(plstr);
-
- modvalues[j] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
- CStringGetDatum(src),
- ObjectIdGetDatum(proc->result.out.r.atts[atti].typelem),
- Int32GetDatum(tupdesc->attrs[j]->atttypmod));
- modnulls[j] = ' ';
-
- Py_DECREF(plstr);
- plstr = NULL;
- }
- Py_DECREF(plval);
- plval = NULL;
-
- }
- rtup = SPI_modifytuple(tdata->tg_relation, otup, natts, modattrs,
- modvalues, modnulls);
-
- /* FIXME -- these leak if not explicity pfree'd by other elog calls, no?
- */
- pfree(modattrs);
- pfree(modvalues);
- pfree(modnulls);
-
- if (rtup == NULL)
- elog(ERROR, "plpython: SPI_modifytuple failed -- error %d", SPI_result);
-
- Py_DECREF(plntup);
- Py_DECREF(plkeys);
-
- RESTORE_EXC();
-
- return rtup;
+ return rtup;
}
PyObject *
-PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
-{
- DECLARE_EXC();
- TriggerData *tdata;
- PyObject *pltname, *pltevent, *pltwhen, *pltlevel, *pltrelid;
- PyObject *pltargs, *pytnew, *pytold;
- PyObject * volatile pltdata = NULL;
- char *stroid;
-
- enter();
-
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
-
- Py_XDECREF(pltdata);
-
- RERAISE_EXC();
- }
-
- tdata = (TriggerData *) fcinfo->context;
-
- pltdata = PyDict_New();
- if (!pltdata)
- PLy_elog(ERROR, "Unable to build arguments for trigger procedure");
-
- pltname = PyString_FromString(tdata->tg_trigger->tgname);
- PyDict_SetItemString(pltdata, "name", pltname);
- Py_DECREF(pltname);
-
- stroid = DatumGetCString(DirectFunctionCall1(oidout,
- ObjectIdGetDatum(tdata->tg_relation->rd_id)));
- pltrelid = PyString_FromString(stroid);
- PyDict_SetItemString(pltdata, "relid", pltrelid);
- Py_DECREF(pltrelid);
- pfree(stroid);
-
-
-
- if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
- pltwhen = PyString_FromString("BEFORE");
- else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
- pltwhen = PyString_FromString("AFTER");
- else
- pltwhen = PyString_FromString("UNKNOWN");
- PyDict_SetItemString(pltdata, "when", pltwhen);
- Py_DECREF(pltwhen);
-
- if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
- pltlevel = PyString_FromString("ROW");
- else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
- pltlevel = PyString_FromString("STATEMENT");
- else
- pltlevel = PyString_FromString("UNKNOWN");
- PyDict_SetItemString(pltdata, "level", pltlevel);
- Py_DECREF(pltlevel);
-
- if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
- {
- pltevent = PyString_FromString("INSERT");
- PyDict_SetItemString(pltdata, "old", Py_None);
- pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "new", pytnew);
- Py_DECREF(pytnew);
- *rv = tdata->tg_trigtuple;
- }
- else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
- {
- pltevent = PyString_FromString("DELETE");
- PyDict_SetItemString(pltdata, "new", Py_None);
- pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "old", pytold);
- Py_DECREF(pytold);
- *rv = tdata->tg_trigtuple;
- }
- else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
- {
- pltevent = PyString_FromString("UPDATE");
- pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "new", pytnew);
- Py_DECREF(pytnew);
- pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "old", pytold);
- Py_DECREF(pytold);
- *rv = tdata->tg_newtuple;
- }
- else
- {
- pltevent = PyString_FromString("UNKNOWN");
- PyDict_SetItemString(pltdata, "old", Py_None);
- PyDict_SetItemString(pltdata, "new", Py_None);
- *rv = tdata->tg_trigtuple;
- }
- PyDict_SetItemString(pltdata, "event", pltevent);
- Py_DECREF(pltevent);
-
- if (tdata->tg_trigger->tgnargs)
- {
- /* all strings...
- */
- int i;
- PyObject *pltarg;
-
- pltargs = PyList_New(tdata->tg_trigger->tgnargs);
- for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
- {
- pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
- /* stolen, don't Py_DECREF
- */
- PyList_SetItem(pltargs, i, pltarg);
- }
- }
- else
- {
- Py_INCREF(Py_None);
- pltargs = Py_None;
- }
- PyDict_SetItemString(pltdata, "args", pltargs);
- Py_DECREF(pltargs);
-
- RESTORE_EXC();
-
- return pltdata;
+PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc, HeapTuple *rv)
+{
+ DECLARE_EXC();
+ TriggerData *tdata;
+ PyObject *pltname,
+ *pltevent,
+ *pltwhen,
+ *pltlevel,
+ *pltrelid;
+ PyObject *pltargs,
+ *pytnew,
+ *pytold;
+ PyObject *volatile pltdata = NULL;
+ char *stroid;
+
+ enter();
+
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+
+ Py_XDECREF(pltdata);
+
+ RERAISE_EXC();
+ }
+
+ tdata = (TriggerData *) fcinfo->context;
+
+ pltdata = PyDict_New();
+ if (!pltdata)
+ PLy_elog(ERROR, "Unable to build arguments for trigger procedure");
+
+ pltname = PyString_FromString(tdata->tg_trigger->tgname);
+ PyDict_SetItemString(pltdata, "name", pltname);
+ Py_DECREF(pltname);
+
+ stroid = DatumGetCString(DirectFunctionCall1(oidout,
+ ObjectIdGetDatum(tdata->tg_relation->rd_id)));
+ pltrelid = PyString_FromString(stroid);
+ PyDict_SetItemString(pltdata, "relid", pltrelid);
+ Py_DECREF(pltrelid);
+ pfree(stroid);
+
+
+
+ if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
+ pltwhen = PyString_FromString("BEFORE");
+ else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
+ pltwhen = PyString_FromString("AFTER");
+ else
+ pltwhen = PyString_FromString("UNKNOWN");
+ PyDict_SetItemString(pltdata, "when", pltwhen);
+ Py_DECREF(pltwhen);
+
+ if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
+ pltlevel = PyString_FromString("ROW");
+ else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
+ pltlevel = PyString_FromString("STATEMENT");
+ else
+ pltlevel = PyString_FromString("UNKNOWN");
+ PyDict_SetItemString(pltdata, "level", pltlevel);
+ Py_DECREF(pltlevel);
+
+ if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
+ {
+ pltevent = PyString_FromString("INSERT");
+ PyDict_SetItemString(pltdata, "old", Py_None);
+ pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "new", pytnew);
+ Py_DECREF(pytnew);
+ *rv = tdata->tg_trigtuple;
+ }
+ else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
+ {
+ pltevent = PyString_FromString("DELETE");
+ PyDict_SetItemString(pltdata, "new", Py_None);
+ pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "old", pytold);
+ Py_DECREF(pytold);
+ *rv = tdata->tg_trigtuple;
+ }
+ else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
+ {
+ pltevent = PyString_FromString("UPDATE");
+ pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "new", pytnew);
+ Py_DECREF(pytnew);
+ pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "old", pytold);
+ Py_DECREF(pytold);
+ *rv = tdata->tg_newtuple;
+ }
+ else
+ {
+ pltevent = PyString_FromString("UNKNOWN");
+ PyDict_SetItemString(pltdata, "old", Py_None);
+ PyDict_SetItemString(pltdata, "new", Py_None);
+ *rv = tdata->tg_trigtuple;
+ }
+ PyDict_SetItemString(pltdata, "event", pltevent);
+ Py_DECREF(pltevent);
+
+ if (tdata->tg_trigger->tgnargs)
+ {
+ /*
+ * all strings...
+ */
+ int i;
+ PyObject *pltarg;
+
+ pltargs = PyList_New(tdata->tg_trigger->tgnargs);
+ for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
+ {
+ pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
+
+ /*
+ * stolen, don't Py_DECREF
+ */
+ PyList_SetItem(pltargs, i, pltarg);
+ }
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ pltargs = Py_None;
+ }
+ PyDict_SetItemString(pltdata, "args", pltargs);
+ Py_DECREF(pltargs);
+
+ RESTORE_EXC();
+
+ return pltdata;
}
@@ -729,176 +763,182 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
/* function handler and friends
*/
Datum
-PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
-{
- DECLARE_EXC();
- Datum rv;
- PyObject * volatile plargs = NULL;
- PyObject * volatile plrv = NULL;
- PyObject * volatile plrv_so = NULL;
- char *plrv_sc;
-
- enter();
-
- /*
- * setup to catch elog in while building function arguments,
- * and DECREF the plargs if the function call fails
- */
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
-
- Py_XDECREF(plargs);
- Py_XDECREF(plrv);
- Py_XDECREF(plrv_so);
-
- RERAISE_EXC();
- }
-
- plargs = PLy_function_build_args(fcinfo, proc);
- plrv = PLy_procedure_call(proc, "args", plargs);
-
- /* Disconnect from SPI manager and then create the return
- * values datum (if the input function does a palloc for it
- * this must not be allocated in the SPI memory context
- * because SPI_finish would free it).
- */
- if (SPI_finish() != SPI_OK_FINISH)
- elog(ERROR, "plpython: SPI_finish failed");
-
- if (plrv == NULL)
- {
- elog(FATAL, "Aiieee, PLy_procedure_call returned NULL");
-#if 0
- if (!PLy_restart_in_progress)
- PLy_elog(ERROR, "plpython: Function \"%s\" failed.", proc->proname);
+PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
+{
+ DECLARE_EXC();
+ Datum rv;
+ PyObject *volatile plargs = NULL;
+ PyObject *volatile plrv = NULL;
+ PyObject *volatile plrv_so = NULL;
+ char *plrv_sc;
+
+ enter();
+
+ /*
+ * setup to catch elog in while building function arguments, and
+ * DECREF the plargs if the function call fails
+ */
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+
+ Py_XDECREF(plargs);
+ Py_XDECREF(plrv);
+ Py_XDECREF(plrv_so);
+
+ RERAISE_EXC();
+ }
+
+ plargs = PLy_function_build_args(fcinfo, proc);
+ plrv = PLy_procedure_call(proc, "args", plargs);
+
+ /*
+ * Disconnect from SPI manager and then create the return values datum
+ * (if the input function does a palloc for it this must not be
+ * allocated in the SPI memory context because SPI_finish would free
+ * it).
+ */
+ if (SPI_finish() != SPI_OK_FINISH)
+ elog(ERROR, "plpython: SPI_finish failed");
- /* FIXME is this dead code? i'm pretty sure it is for unnested
- * calls, but not for nested calls
- */
- RAISE_EXC(1);
+ if (plrv == NULL)
+ {
+ elog(FATAL, "Aiieee, PLy_procedure_call returned NULL");
+#if 0
+ if (!PLy_restart_in_progress)
+ PLy_elog(ERROR, "plpython: Function \"%s\" failed.", proc->proname);
+
+ /*
+ * FIXME is this dead code? i'm pretty sure it is for unnested
+ * calls, but not for nested calls
+ */
+ RAISE_EXC(1);
#endif
- }
-
- /* convert the python PyObject to a postgresql Datum
- * FIXME returning a NULL, ie PG_RETURN_NULL() blows the backend
- * to small messy bits... it this a bug or expected? so just
- * call with the string value of None for now
- */
-
- if (plrv == Py_None)
- {
- fcinfo->isnull = true;
- rv = (Datum) NULL;
- }
- else
- {
- fcinfo->isnull = false;
- plrv_so = PyObject_Str(plrv);
- plrv_sc = PyString_AsString(plrv_so);
- rv = FunctionCall3(&proc->result.out.d.typfunc,
- PointerGetDatum(plrv_sc),
- ObjectIdGetDatum(proc->result.out.d.typelem),
- Int32GetDatum(-1));
- }
-
- RESTORE_EXC();
-
- Py_XDECREF(plargs);
- Py_DECREF(plrv);
- Py_XDECREF(plrv_so);
-
- return rv;
-}
+ }
-PyObject *
-PLy_procedure_call(PLyProcedure *proc, char *kargs, PyObject *vargs)
-{
- PyObject *rv;
-
- enter();
+ /*
+ * convert the python PyObject to a postgresql Datum FIXME returning a
+ * NULL, ie PG_RETURN_NULL() blows the backend to small messy bits...
+ * it this a bug or expected? so just call with the string value of
+ * None for now
+ */
+
+ if (plrv == Py_None)
+ {
+ fcinfo->isnull = true;
+ rv = (Datum) NULL;
+ }
+ else
+ {
+ fcinfo->isnull = false;
+ plrv_so = PyObject_Str(plrv);
+ plrv_sc = PyString_AsString(plrv_so);
+ rv = FunctionCall3(&proc->result.out.d.typfunc,
+ PointerGetDatum(plrv_sc),
+ ObjectIdGetDatum(proc->result.out.d.typelem),
+ Int32GetDatum(-1));
+ }
- PyDict_SetItemString(proc->globals, kargs, vargs);
- rv = PyObject_CallFunction(proc->reval, "O", proc->code);
+ RESTORE_EXC();
- if ((rv == NULL) || (PyErr_Occurred()))
- {
- Py_XDECREF(rv);
- if (!PLy_restart_in_progress)
- PLy_elog(ERROR, "Call of function `%s' failed.", proc->proname);
- RAISE_EXC(1);
- }
+ Py_XDECREF(plargs);
+ Py_DECREF(plrv);
+ Py_XDECREF(plrv_so);
- return rv;
+ return rv;
}
PyObject *
-PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
+PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
{
- DECLARE_EXC();
- PyObject * volatile arg = NULL;
- PyObject * volatile args = NULL;
- int i;
+ PyObject *rv;
- enter();
+ enter();
- /* FIXME -- if the setjmp setup is expensive, add the arg and
- * args field to the procedure struct and cleanup at the
- * start of the next call
- */
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
- Py_XDECREF(arg);
- Py_XDECREF(args);
+ PyDict_SetItemString(proc->globals, kargs, vargs);
+ rv = PyObject_CallFunction(proc->reval, "O", proc->code);
- RERAISE_EXC();
- }
-
- args = PyList_New(proc->nargs);
- for (i = 0; i < proc->nargs; i++)
- {
- if (proc->args[i].is_rel == 1)
+ if ((rv == NULL) || (PyErr_Occurred()))
{
- TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];
- arg = PLyDict_FromTuple(&(proc->args[i]), slot->val,
- slot->ttc_tupleDescriptor);
+ Py_XDECREF(rv);
+ if (!PLy_restart_in_progress)
+ PLy_elog(ERROR, "Call of function `%s' failed.", proc->proname);
+ RAISE_EXC(1);
}
- else
+
+ return rv;
+}
+
+PyObject *
+PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
+{
+ DECLARE_EXC();
+ PyObject *volatile arg = NULL;
+ PyObject *volatile args = NULL;
+ int i;
+
+ enter();
+
+ /*
+ * FIXME -- if the setjmp setup is expensive, add the arg and args
+ * field to the procedure struct and cleanup at the start of the next
+ * call
+ */
+ SAVE_EXC();
+ if (TRAP_EXC())
{
- if (!fcinfo->argnull[i])
- {
- char *ct;
- Datum dt;
+ RESTORE_EXC();
+ Py_XDECREF(arg);
+ Py_XDECREF(args);
- dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
- fcinfo->arg[i],
- ObjectIdGetDatum(proc->args[i].in.d.typelem),
- Int32GetDatum(-1));
- ct = DatumGetCString(dt);
- arg = (proc->args[i].in.d.func)(ct);
- pfree(ct);
- }
- else
- arg = NULL;
+ RERAISE_EXC();
}
- if (arg == NULL)
+ args = PyList_New(proc->nargs);
+ for (i = 0; i < proc->nargs; i++)
{
- Py_INCREF(Py_None);
- arg = Py_None;
- }
+ if (proc->args[i].is_rel == 1)
+ {
+ TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];
- /* FIXME -- error check this
- */
- PyList_SetItem(args, i, arg);
- }
+ arg = PLyDict_FromTuple(&(proc->args[i]), slot->val,
+ slot->ttc_tupleDescriptor);
+ }
+ else
+ {
+ if (!fcinfo->argnull[i])
+ {
+ char *ct;
+ Datum dt;
+
+ dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
+ fcinfo->arg[i],
+ ObjectIdGetDatum(proc->args[i].in.d.typelem),
+ Int32GetDatum(-1));
+ ct = DatumGetCString(dt);
+ arg = (proc->args[i].in.d.func) (ct);
+ pfree(ct);
+ }
+ else
+ arg = NULL;
+ }
- RESTORE_EXC();
+ if (arg == NULL)
+ {
+ Py_INCREF(Py_None);
+ arg = Py_None;
+ }
- return args;
+ /*
+ * FIXME -- error check this
+ */
+ PyList_SetItem(args, i, arg);
+ }
+
+ RESTORE_EXC();
+
+ return args;
}
@@ -907,532 +947,552 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
static PLyProcedure *
PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
{
- Oid fn_oid;
- HeapTuple procTup;
- char key[128];
- PyObject *plproc;
- PLyProcedure *proc = NULL;
- int rv;
-
- enter();
-
- fn_oid = fcinfo->flinfo->fn_oid;
- procTup = SearchSysCache(PROCOID,
- ObjectIdGetDatum(fn_oid),
- 0, 0, 0);
- if (!HeapTupleIsValid(procTup))
- elog(ERROR, "plpython: cache lookup for procedure %u failed", fn_oid);
-
- rv = snprintf(key, sizeof(key), "%u%s",
- fn_oid,
- is_trigger ? "_trigger" : "");
- if ((rv >= sizeof(key)) || (rv < 0))
- elog(FATAL, "plpython: Buffer overrun in %s:%d", __FILE__, __LINE__);
-
- plproc = PyDict_GetItemString(PLy_procedure_cache, key);
-
- if (plproc != NULL)
- {
- Py_INCREF(plproc);
- if (!PyCObject_Check(plproc))
- elog(FATAL, "plpython: Expected a PyCObject, didn't get one");
-
- mark();
-
- proc = PyCObject_AsVoidPtr(plproc);
- if (proc->me != plproc)
- elog(FATAL, "plpython: Aiieee, proc->me != plproc");
- /* did we find an up-to-date cache entry? */
- if (proc->fn_xmin != procTup->t_data->t_xmin ||
- proc->fn_cmin != procTup->t_data->t_cmin)
- {
- Py_DECREF(plproc);
- proc = NULL;
- }
- }
-
- if (proc == NULL)
- proc = PLy_procedure_create(fcinfo, is_trigger, procTup, key);
-
- ReleaseSysCache(procTup);
-
- return proc;
+ Oid fn_oid;
+ HeapTuple procTup;
+ char key[128];
+ PyObject *plproc;
+ PLyProcedure *proc = NULL;
+ int rv;
+
+ enter();
+
+ fn_oid = fcinfo->flinfo->fn_oid;
+ procTup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(fn_oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(procTup))
+ elog(ERROR, "plpython: cache lookup for procedure %u failed", fn_oid);
+
+ rv = snprintf(key, sizeof(key), "%u%s",
+ fn_oid,
+ is_trigger ? "_trigger" : "");
+ if ((rv >= sizeof(key)) || (rv < 0))
+ elog(FATAL, "plpython: Buffer overrun in %s:%d", __FILE__, __LINE__);
+
+ plproc = PyDict_GetItemString(PLy_procedure_cache, key);
+
+ if (plproc != NULL)
+ {
+ Py_INCREF(plproc);
+ if (!PyCObject_Check(plproc))
+ elog(FATAL, "plpython: Expected a PyCObject, didn't get one");
+
+ mark();
+
+ proc = PyCObject_AsVoidPtr(plproc);
+ if (proc->me != plproc)
+ elog(FATAL, "plpython: Aiieee, proc->me != plproc");
+ /* did we find an up-to-date cache entry? */
+ if (proc->fn_xmin != procTup->t_data->t_xmin ||
+ proc->fn_cmin != procTup->t_data->t_cmin)
+ {
+ Py_DECREF(plproc);
+ proc = NULL;
+ }
+ }
+
+ if (proc == NULL)
+ proc = PLy_procedure_create(fcinfo, is_trigger, procTup, key);
+
+ ReleaseSysCache(procTup);
+
+ return proc;
}
static PLyProcedure *
PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
HeapTuple procTup, char *key)
{
- char procName[256];
- DECLARE_EXC();
- Form_pg_proc procStruct;
- PLyProcedure *volatile proc;
- char *volatile procSource = NULL;
- Datum procDatum;
- int i, rv;
-
- enter();
-
- procStruct = (Form_pg_proc) GETSTRUCT(procTup);
-
- rv = snprintf(procName, sizeof(procName),
- "__plpython_procedure_%s_%u%s",
- NameStr(procStruct->proname),
- fcinfo->flinfo->fn_oid,
- is_trigger ? "_trigger" : "");
- if ((rv >= sizeof(procName)) || (rv < 0))
- elog(FATAL, "plpython: Procedure name would overrun buffer");
-
- proc = PLy_malloc(sizeof(PLyProcedure));
- proc->proname = PLy_malloc(strlen(procName) + 1);
- strcpy(proc->proname, procName);
- proc->fn_xmin = procTup->t_data->t_xmin;
- proc->fn_cmin = procTup->t_data->t_cmin;
- PLy_typeinfo_init(&proc->result);
- for (i = 0; i < FUNC_MAX_ARGS; i++)
- PLy_typeinfo_init(&proc->args[i]);
- proc->nargs = 0;
- proc->code = proc->interp = proc->reval = proc->statics = NULL;
- proc->globals = proc->me = NULL;
-
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
- PLy_procedure_delete(proc);
- if (procSource)
+ char procName[256];
+
+ DECLARE_EXC();
+ Form_pg_proc procStruct;
+ PLyProcedure *volatile proc;
+ char *volatile procSource = NULL;
+ Datum procDatum;
+ int i,
+ rv;
+
+ enter();
+
+ procStruct = (Form_pg_proc) GETSTRUCT(procTup);
+
+ rv = snprintf(procName, sizeof(procName),
+ "__plpython_procedure_%s_%u%s",
+ NameStr(procStruct->proname),
+ fcinfo->flinfo->fn_oid,
+ is_trigger ? "_trigger" : "");
+ if ((rv >= sizeof(procName)) || (rv < 0))
+ elog(FATAL, "plpython: Procedure name would overrun buffer");
+
+ proc = PLy_malloc(sizeof(PLyProcedure));
+ proc->proname = PLy_malloc(strlen(procName) + 1);
+ strcpy(proc->proname, procName);
+ proc->fn_xmin = procTup->t_data->t_xmin;
+ proc->fn_cmin = procTup->t_data->t_cmin;
+ PLy_typeinfo_init(&proc->result);
+ for (i = 0; i < FUNC_MAX_ARGS; i++)
+ PLy_typeinfo_init(&proc->args[i]);
+ proc->nargs = 0;
+ proc->code = proc->interp = proc->reval = proc->statics = NULL;
+ proc->globals = proc->me = NULL;
+
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+ PLy_procedure_delete(proc);
+ if (procSource)
+ pfree(procSource);
+ RERAISE_EXC();
+ }
+
+ /*
+ * get information required for output conversion of the return value,
+ * but only if this isn't a trigger.
+ */
+ if (!is_trigger)
+ {
+ HeapTuple rvTypeTup;
+ Form_pg_type rvTypeStruct;
+ Datum rvDatum;
+
+ rvDatum = ObjectIdGetDatum(procStruct->prorettype);
+ rvTypeTup = SearchSysCache(TYPEOID, rvDatum, 0, 0, 0);
+ if (!HeapTupleIsValid(rvTypeTup))
+ elog(ERROR, "plpython: cache lookup for type \"%u\" failed",
+ procStruct->prorettype);
+
+ rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
+ if (rvTypeStruct->typrelid == InvalidOid)
+ PLy_output_datum_func(&proc->result, rvTypeStruct);
+ else
+ elog(ERROR, "plpython: tuple return types not supported, yet");
+
+ ReleaseSysCache(rvTypeTup);
+ }
+ else
+ {
+ /*
+ * input/output conversion for trigger tuples. use the result
+ * TypeInfo variable to store the tuple conversion info.
+ */
+ TriggerData *tdata = (TriggerData *) fcinfo->context;
+
+ PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
+ PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
+ }
+
+ /*
+ * now get information required for input conversion of the procedures
+ * arguments.
+ */
+ proc->nargs = fcinfo->nargs;
+ for (i = 0; i < fcinfo->nargs; i++)
+ {
+ HeapTuple argTypeTup;
+ Form_pg_type argTypeStruct;
+ Datum argDatum;
+
+ argDatum = ObjectIdGetDatum(procStruct->proargtypes[i]);
+ argTypeTup = SearchSysCache(TYPEOID, argDatum, 0, 0, 0);
+ if (!HeapTupleIsValid(argTypeTup))
+ elog(ERROR, "plpython: cache lookup for type \"%u\" failed",
+ procStruct->proargtypes[i]);
+ argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
+
+ if (argTypeStruct->typrelid == InvalidOid)
+ PLy_input_datum_func(&(proc->args[i]), argTypeStruct);
+ else
+ {
+ TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];
+
+ PLy_input_tuple_funcs(&(proc->args[i]),
+ slot->ttc_tupleDescriptor);
+ }
+
+ ReleaseSysCache(argTypeTup);
+ }
+
+
+ /*
+ * get the text of the function.
+ */
+ procDatum = DirectFunctionCall1(textout,
+ PointerGetDatum(&procStruct->prosrc));
+ procSource = DatumGetCString(procDatum);
+
+ PLy_procedure_compile(proc, procSource);
+
pfree(procSource);
- RERAISE_EXC();
- }
-
- /* get information required for output conversion of the return
- * value, but only if this isn't a trigger.
- */
- if (!is_trigger)
- {
- HeapTuple rvTypeTup;
- Form_pg_type rvTypeStruct;
- Datum rvDatum;
-
- rvDatum = ObjectIdGetDatum(procStruct->prorettype);
- rvTypeTup = SearchSysCache(TYPEOID, rvDatum, 0, 0, 0);
- if (!HeapTupleIsValid(rvTypeTup))
- elog(ERROR, "plpython: cache lookup for type \"%u\" failed",
- procStruct->prorettype);
-
- rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
- if (rvTypeStruct->typrelid == InvalidOid)
- PLy_output_datum_func(&proc->result, rvTypeStruct);
- else
- elog(ERROR, "plpython: tuple return types not supported, yet");
-
- ReleaseSysCache(rvTypeTup);
- }
- else
- {
- /* input/output conversion for trigger tuples. use the
- * result TypeInfo variable to store the tuple conversion
- * info.
- */
- TriggerData *tdata = (TriggerData *) fcinfo->context;
- PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
- PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
- }
-
- /* now get information required for input conversion of the
- * procedures arguments.
- */
- proc->nargs = fcinfo->nargs;
- for (i = 0; i < fcinfo->nargs; i++)
- {
- HeapTuple argTypeTup;
- Form_pg_type argTypeStruct;
- Datum argDatum;
-
- argDatum = ObjectIdGetDatum(procStruct->proargtypes[i]);
- argTypeTup = SearchSysCache(TYPEOID, argDatum, 0, 0, 0);
- if (!HeapTupleIsValid(argTypeTup))
- elog(ERROR, "plpython: cache lookup for type \"%u\" failed",
- procStruct->proargtypes[i]);
- argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
-
- if (argTypeStruct->typrelid == InvalidOid)
- PLy_input_datum_func(&(proc->args[i]), argTypeStruct);
- else
- {
- TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];
- PLy_input_tuple_funcs(&(proc->args[i]),
- slot->ttc_tupleDescriptor);
- }
-
- ReleaseSysCache(argTypeTup);
- }
-
-
- /* get the text of the function.
- */
- procDatum = DirectFunctionCall1(textout,
- PointerGetDatum(&procStruct->prosrc));
- procSource = DatumGetCString(procDatum);
-
- PLy_procedure_compile(proc, procSource);
-
- pfree(procSource);
-
- proc->me = PyCObject_FromVoidPtr(proc, NULL);
- PyDict_SetItemString(PLy_procedure_cache, key, proc->me);
-
- RESTORE_EXC();
-
- return proc;
+
+ proc->me = PyCObject_FromVoidPtr(proc, NULL);
+ PyDict_SetItemString(PLy_procedure_cache, key, proc->me);
+
+ RESTORE_EXC();
+
+ return proc;
}
void
-PLy_procedure_compile(PLyProcedure *proc, const char *src)
-{
- PyObject *module, *crv = NULL;
- char *msrc;
-
- enter();
-
- /* get an instance of rexec.RExec for the function
- */
- proc->interp = PyObject_CallMethod(PLy_interp_safe, "RExec", NULL);
- if ((proc->interp == NULL) || (PyErr_Occurred ()))
- PLy_elog(ERROR, "Unable to create rexec.RExec instance");
-
- /* tweak the list of permitted modules
- */
- PyObject_SetAttrString(proc->interp, "ok_builtin_modules",
- PLy_importable_modules);
-
- proc->reval = PyObject_GetAttrString(proc->interp, "r_eval");
- if ((proc->reval == NULL) || (PyErr_Occurred ()))
- PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec");
-
- /* add a __main__ module to the function's interpreter
- */
- module = PyObject_CallMethod (proc->interp, "add_module", "s", "__main__");
- if ((module == NULL) || (PyErr_Occurred ()))
- PLy_elog(ERROR, "Unable to get module `__main__' from rexec.RExec");
-
- /* add plpy module to the interpreters main dictionary
- */
- proc->globals = PyModule_GetDict (module);
- if ((proc->globals == NULL) || (PyErr_Occurred ()))
- PLy_elog(ERROR, "Unable to get `__main__.__dict__' from rexec.RExec");
-
- /* why the hell won't r_import or r_exec('import plpy') work?
- */
- module = PyDict_GetItemString(PLy_interp_globals, "plpy");
- if ((module == NULL) || (PyErr_Occurred()))
- PLy_elog(ERROR, "Unable to get `plpy'");
- Py_INCREF(module);
- PyDict_SetItemString(proc->globals, "plpy", module);
-
- /* SD is private preserved data between calls
- * GD is global data shared by all functions
- */
- proc->statics = PyDict_New();
- PyDict_SetItemString(proc->globals, "SD", proc->statics);
- PyDict_SetItemString(proc->globals, "GD", PLy_interp_safe_globals);
-
- /* insert the function code into the interpreter
- */
- msrc = PLy_procedure_munge_source(proc->proname, src);
- crv = PyObject_CallMethod(proc->interp, "r_exec", "s", msrc);
- free(msrc);
-
- if ((crv != NULL) && (!PyErr_Occurred ()))
- {
- int clen;
- char call[256];
-
- Py_DECREF(crv);
-
- /* compile a call to the function
- */
- clen = snprintf(call, sizeof(call), "%s()", proc->proname);
- if ((clen < 0) || (clen >= sizeof(call)))
- elog(ERROR, "plpython: string would overflow buffer.");
- proc->code = Py_CompileString(call, "<string>", Py_eval_input);
- if ((proc->code != NULL) && (!PyErr_Occurred ()))
- return;
- }
- else
- Py_XDECREF(crv);
-
- PLy_elog(ERROR, "Unable to compile function %s", proc->proname);
+PLy_procedure_compile(PLyProcedure * proc, const char *src)
+{
+ PyObject *module,
+ *crv = NULL;
+ char *msrc;
+
+ enter();
+
+ /*
+ * get an instance of rexec.RExec for the function
+ */
+ proc->interp = PyObject_CallMethod(PLy_interp_safe, "RExec", NULL);
+ if ((proc->interp == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to create rexec.RExec instance");
+
+ /*
+ * tweak the list of permitted modules
+ */
+ PyObject_SetAttrString(proc->interp, "ok_builtin_modules",
+ PLy_importable_modules);
+
+ proc->reval = PyObject_GetAttrString(proc->interp, "r_eval");
+ if ((proc->reval == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec");
+
+ /*
+ * add a __main__ module to the function's interpreter
+ */
+ module = PyObject_CallMethod(proc->interp, "add_module", "s", "__main__");
+ if ((module == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to get module `__main__' from rexec.RExec");
+
+ /*
+ * add plpy module to the interpreters main dictionary
+ */
+ proc->globals = PyModule_GetDict(module);
+ if ((proc->globals == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to get `__main__.__dict__' from rexec.RExec");
+
+ /*
+ * why the hell won't r_import or r_exec('import plpy') work?
+ */
+ module = PyDict_GetItemString(PLy_interp_globals, "plpy");
+ if ((module == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to get `plpy'");
+ Py_INCREF(module);
+ PyDict_SetItemString(proc->globals, "plpy", module);
+
+ /*
+ * SD is private preserved data between calls GD is global data shared
+ * by all functions
+ */
+ proc->statics = PyDict_New();
+ PyDict_SetItemString(proc->globals, "SD", proc->statics);
+ PyDict_SetItemString(proc->globals, "GD", PLy_interp_safe_globals);
+
+ /*
+ * insert the function code into the interpreter
+ */
+ msrc = PLy_procedure_munge_source(proc->proname, src);
+ crv = PyObject_CallMethod(proc->interp, "r_exec", "s", msrc);
+ free(msrc);
+
+ if ((crv != NULL) && (!PyErr_Occurred()))
+ {
+ int clen;
+ char call[256];
+
+ Py_DECREF(crv);
+
+ /*
+ * compile a call to the function
+ */
+ clen = snprintf(call, sizeof(call), "%s()", proc->proname);
+ if ((clen < 0) || (clen >= sizeof(call)))
+ elog(ERROR, "plpython: string would overflow buffer.");
+ proc->code = Py_CompileString(call, "<string>", Py_eval_input);
+ if ((proc->code != NULL) && (!PyErr_Occurred()))
+ return;
+ }
+ else
+ Py_XDECREF(crv);
+
+ PLy_elog(ERROR, "Unable to compile function %s", proc->proname);
}
char *
PLy_procedure_munge_source(const char *name, const char *src)
{
- char *mrc, *mp;
- const char *sp;
- size_t mlen, plen;
+ char *mrc,
+ *mp;
+ const char *sp;
+ size_t mlen,
+ plen;
- enter();
+ enter();
- /* room for function source and the def statement
- */
- mlen = (strlen (src) * 2) + strlen(name) + 16;
+ /*
+ * room for function source and the def statement
+ */
+ mlen = (strlen(src) * 2) + strlen(name) + 16;
- mrc = PLy_malloc(mlen);
- plen = snprintf(mrc, mlen, "def %s():\n\t", name);
- if ((plen < 0) || (plen >= mlen))
- elog(FATAL, "Aiieee, impossible buffer overrun (or snprintf failure)");
+ mrc = PLy_malloc(mlen);
+ plen = snprintf(mrc, mlen, "def %s():\n\t", name);
+ if ((plen < 0) || (plen >= mlen))
+ elog(FATAL, "Aiieee, impossible buffer overrun (or snprintf failure)");
- sp = src;
- mp = mrc + plen;
+ sp = src;
+ mp = mrc + plen;
- while (*sp != '\0')
- {
- if (*sp == '\n')
+ while (*sp != '\0')
{
- *mp++ = *sp++;
- *mp++ = '\t';
+ if (*sp == '\n')
+ {
+ *mp++ = *sp++;
+ *mp++ = '\t';
+ }
+ else
+ *mp++ = *sp++;
}
- else
- *mp++ = *sp++;
- }
- *mp++ = '\n';
- *mp++ = '\n';
- *mp = '\0';
+ *mp++ = '\n';
+ *mp++ = '\n';
+ *mp = '\0';
- if (mp > (mrc + mlen))
- elog(FATAL, "plpython: Buffer overrun in PLy_munge_source");
+ if (mp > (mrc + mlen))
+ elog(FATAL, "plpython: Buffer overrun in PLy_munge_source");
- return mrc;
+ return mrc;
}
void
-PLy_procedure_delete(PLyProcedure *proc)
-{
- int i;
-
- enter();
-
- Py_XDECREF(proc->code);
- Py_XDECREF(proc->interp);
- Py_XDECREF(proc->reval);
- Py_XDECREF(proc->statics);
- Py_XDECREF(proc->globals);
- Py_XDECREF(proc->me);
- if (proc->proname)
- PLy_free(proc->proname);
- for (i = 0; i < proc->nargs; i++)
- if (proc->args[i].is_rel == 1)
- {
- if (proc->args[i].in.r.atts)
- PLy_free(proc->args[i].in.r.atts);
- if (proc->args[i].out.r.atts)
- PLy_free(proc->args[i].out.r.atts);
- }
+PLy_procedure_delete(PLyProcedure * proc)
+{
+ int i;
+
+ enter();
+
+ Py_XDECREF(proc->code);
+ Py_XDECREF(proc->interp);
+ Py_XDECREF(proc->reval);
+ Py_XDECREF(proc->statics);
+ Py_XDECREF(proc->globals);
+ Py_XDECREF(proc->me);
+ if (proc->proname)
+ PLy_free(proc->proname);
+ for (i = 0; i < proc->nargs; i++)
+ if (proc->args[i].is_rel == 1)
+ {
+ if (proc->args[i].in.r.atts)
+ PLy_free(proc->args[i].in.r.atts);
+ if (proc->args[i].out.r.atts)
+ PLy_free(proc->args[i].out.r.atts);
+ }
- leave();
+ leave();
}
/* conversion functions. remember output from python is
* input to postgresql, and vis versa.
*/
void
-PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
+PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
{
- int i;
- Datum datum;
-
- enter ();
+ int i;
+ Datum datum;
- if (arg->is_rel == 0)
- elog(FATAL, "plpython: PLyTypeInfo struct is initialized for a Datum");
+ enter();
- arg->is_rel = 1;
- arg->in.r.natts = desc->natts;
- arg->in.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb));
+ if (arg->is_rel == 0)
+ elog(FATAL, "plpython: PLyTypeInfo struct is initialized for a Datum");
- for (i = 0; i < desc->natts; i++)
- {
- HeapTuple typeTup;
- Form_pg_type typeStruct;
+ arg->is_rel = 1;
+ arg->in.r.natts = desc->natts;
+ arg->in.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb));
- datum = ObjectIdGetDatum(desc->attrs[i]->atttypid);
- typeTup = SearchSysCache(TYPEOID, datum, 0, 0, 0);
- if (!HeapTupleIsValid(typeTup))
+ for (i = 0; i < desc->natts; i++)
{
- char *attname = NameStr(desc->attrs[i]->attname);
- elog(ERROR, "plpython: Cache lookup for attribute `%s' type `%u' failed",
- attname, desc->attrs[i]->atttypid);
- }
+ HeapTuple typeTup;
+ Form_pg_type typeStruct;
+
+ datum = ObjectIdGetDatum(desc->attrs[i]->atttypid);
+ typeTup = SearchSysCache(TYPEOID, datum, 0, 0, 0);
+ if (!HeapTupleIsValid(typeTup))
+ {
+ char *attname = NameStr(desc->attrs[i]->attname);
+
+ elog(ERROR, "plpython: Cache lookup for attribute `%s' type `%u' failed",
+ attname, desc->attrs[i]->atttypid);
+ }
- typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
- PLy_input_datum_func2(&(arg->in.r.atts[i]), typeStruct);
+ PLy_input_datum_func2(&(arg->in.r.atts[i]), typeStruct);
- ReleaseSysCache(typeTup);
- }
+ ReleaseSysCache(typeTup);
+ }
}
void
-PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
+PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
{
- int i;
- Datum datum;
-
- enter ();
+ int i;
+ Datum datum;
- if (arg->is_rel == 0)
- elog(FATAL, "plpython: PLyTypeInfo struct is initialized for a Datum");
+ enter();
- arg->is_rel = 1;
- arg->out.r.natts = desc->natts;
- arg->out.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb));
+ if (arg->is_rel == 0)
+ elog(FATAL, "plpython: PLyTypeInfo struct is initialized for a Datum");
- for (i = 0; i < desc->natts; i++)
- {
- HeapTuple typeTup;
- Form_pg_type typeStruct;
+ arg->is_rel = 1;
+ arg->out.r.natts = desc->natts;
+ arg->out.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb));
- datum = ObjectIdGetDatum(desc->attrs[i]->atttypid);
- typeTup = SearchSysCache(TYPEOID, datum, 0, 0, 0);
- if (!HeapTupleIsValid(typeTup))
+ for (i = 0; i < desc->natts; i++)
{
- char *attname = NameStr(desc->attrs[i]->attname);
- elog(ERROR, "plpython: Cache lookup for attribute `%s' type `%u' failed",
- attname, desc->attrs[i]->atttypid);
- }
+ HeapTuple typeTup;
+ Form_pg_type typeStruct;
+
+ datum = ObjectIdGetDatum(desc->attrs[i]->atttypid);
+ typeTup = SearchSysCache(TYPEOID, datum, 0, 0, 0);
+ if (!HeapTupleIsValid(typeTup))
+ {
+ char *attname = NameStr(desc->attrs[i]->attname);
+
+ elog(ERROR, "plpython: Cache lookup for attribute `%s' type `%u' failed",
+ attname, desc->attrs[i]->atttypid);
+ }
- typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
- PLy_output_datum_func2(&(arg->out.r.atts[i]), typeStruct);
+ PLy_output_datum_func2(&(arg->out.r.atts[i]), typeStruct);
- ReleaseSysCache(typeTup);
- }
+ ReleaseSysCache(typeTup);
+ }
}
void
-PLy_output_datum_func(PLyTypeInfo *arg, Form_pg_type typeStruct)
+PLy_output_datum_func(PLyTypeInfo * arg, Form_pg_type typeStruct)
{
- enter();
+ enter();
- if (arg->is_rel == 1)
- elog(FATAL, "plpython: PLyTypeInfo struct is initialized for a Tuple");
- arg->is_rel = 0;
- PLy_output_datum_func2(&(arg->out.d), typeStruct);
+ if (arg->is_rel == 1)
+ elog(FATAL, "plpython: PLyTypeInfo struct is initialized for a Tuple");
+ arg->is_rel = 0;
+ PLy_output_datum_func2(&(arg->out.d), typeStruct);
}
void
-PLy_output_datum_func2(PLyObToDatum *arg, Form_pg_type typeStruct)
+PLy_output_datum_func2(PLyObToDatum * arg, Form_pg_type typeStruct)
{
- enter();
+ enter();
- perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
- arg->typelem = typeStruct->typelem;
- arg->typbyval = typeStruct->typbyval;
+ perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
+ arg->typelem = typeStruct->typelem;
+ arg->typbyval = typeStruct->typbyval;
}
void
-PLy_input_datum_func(PLyTypeInfo *arg, Form_pg_type typeStruct)
+PLy_input_datum_func(PLyTypeInfo * arg, Form_pg_type typeStruct)
{
- enter();
+ enter();
- if (arg->is_rel == 1)
- elog(FATAL, "plpython: PLyTypeInfo struct is initialized for Tuple");
- arg->is_rel = 0;
- PLy_input_datum_func2(&(arg->in.d), typeStruct);
+ if (arg->is_rel == 1)
+ elog(FATAL, "plpython: PLyTypeInfo struct is initialized for Tuple");
+ arg->is_rel = 0;
+ PLy_input_datum_func2(&(arg->in.d), typeStruct);
}
void
-PLy_input_datum_func2(PLyDatumToOb *arg, Form_pg_type typeStruct)
-{
- char *type;
-
- perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
- arg->typelem = typeStruct->typelem;
- arg->typbyval = typeStruct->typbyval;
-
- /* hmmm, wierd. means this arg will always be converted
- * to a python None
- */
- if (!OidIsValid(typeStruct->typoutput))
- {
- elog(ERROR, "plpython: (FIXME) typeStruct->typoutput is invalid");
-
- arg->func = NULL;
- return;
- }
-
- type = NameStr(typeStruct->typname);
- switch (type[0])
- {
- case 'b':
- {
- if (strcasecmp("bool", type))
- {
- arg->func = PLyBool_FromString;
- return;
- }
- break;
- }
- case 'f':
- {
- if ((strncasecmp("float", type, 5) == 0) &&
- ((type[5] == '8') || (type[5] == '4')))
- {
- arg->func = PLyFloat_FromString;
- return;
- }
- break;
- }
- case 'i':
- {
- if ((strncasecmp("int", type, 3) == 0) &&
- ((type[3] == '4') || (type[3] == '2')) &&
- (type[4] == '\0'))
- {
- arg->func = PLyInt_FromString;
- return;
- }
- else if ( strcasecmp("int8", type) == 0 )
- {
- arg->func = PLyLong_FromString;
- }
- break;
- }
- case 'n':
- {
- if (strcasecmp("numeric", type) == 0)
- {
- arg->func = PLyFloat_FromString;
- return;
- }
- break;
- }
- default:
- break;
- }
- arg->func = PLyString_FromString;
+PLy_input_datum_func2(PLyDatumToOb * arg, Form_pg_type typeStruct)
+{
+ char *type;
+
+ perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
+ arg->typelem = typeStruct->typelem;
+ arg->typbyval = typeStruct->typbyval;
+
+ /*
+ * hmmm, wierd. means this arg will always be converted to a python
+ * None
+ */
+ if (!OidIsValid(typeStruct->typoutput))
+ {
+ elog(ERROR, "plpython: (FIXME) typeStruct->typoutput is invalid");
+
+ arg->func = NULL;
+ return;
+ }
+
+ type = NameStr(typeStruct->typname);
+ switch (type[0])
+ {
+ case 'b':
+ {
+ if (strcasecmp("bool", type))
+ {
+ arg->func = PLyBool_FromString;
+ return;
+ }
+ break;
+ }
+ case 'f':
+ {
+ if ((strncasecmp("float", type, 5) == 0) &&
+ ((type[5] == '8') || (type[5] == '4')))
+ {
+ arg->func = PLyFloat_FromString;
+ return;
+ }
+ break;
+ }
+ case 'i':
+ {
+ if ((strncasecmp("int", type, 3) == 0) &&
+ ((type[3] == '4') || (type[3] == '2')) &&
+ (type[4] == '\0'))
+ {
+ arg->func = PLyInt_FromString;
+ return;
+ }
+ else if (strcasecmp("int8", type) == 0)
+ arg->func = PLyLong_FromString;
+ break;
+ }
+ case 'n':
+ {
+ if (strcasecmp("numeric", type) == 0)
+ {
+ arg->func = PLyFloat_FromString;
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ arg->func = PLyString_FromString;
}
void
-PLy_typeinfo_init(PLyTypeInfo *arg)
+PLy_typeinfo_init(PLyTypeInfo * arg)
{
- arg->is_rel = -1;
- arg->in.r.natts = arg->out.r.natts = 0;
- arg->in.r.atts = NULL;
- arg->out.r.atts = NULL;
+ arg->is_rel = -1;
+ arg->in.r.natts = arg->out.r.natts = 0;
+ arg->in.r.atts = NULL;
+ arg->out.r.atts = NULL;
}
void
-PLy_typeinfo_dealloc(PLyTypeInfo *arg)
+PLy_typeinfo_dealloc(PLyTypeInfo * arg)
{
- if (arg->is_rel == 1)
- {
- if (arg->in.r.atts)
- PLy_free(arg->in.r.atts);
- if (arg->out.r.atts)
- PLy_free(arg->out.r.atts);
- }
+ if (arg->is_rel == 1)
+ {
+ if (arg->in.r.atts)
+ PLy_free(arg->in.r.atts);
+ if (arg->out.r.atts)
+ PLy_free(arg->out.r.atts);
+ }
}
/* assumes that a bool is always returned as a 't' or 'f'
@@ -1440,112 +1500,115 @@ PLy_typeinfo_dealloc(PLyTypeInfo *arg)
PyObject *
PLyBool_FromString(const char *src)
{
- enter();
+ enter();
- if (src[0] == 't')
- return PyInt_FromLong(1);
- return PyInt_FromLong(0);
+ if (src[0] == 't')
+ return PyInt_FromLong(1);
+ return PyInt_FromLong(0);
}
PyObject *
PLyFloat_FromString(const char *src)
{
- double v;
- char *eptr;
+ double v;
+ char *eptr;
+
+ enter();
- enter();
-
- errno = 0;
- v = strtod(src, &eptr);
- if ((*eptr != '\0') || (errno))
- return NULL;
- return PyFloat_FromDouble(v);
+ errno = 0;
+ v = strtod(src, &eptr);
+ if ((*eptr != '\0') || (errno))
+ return NULL;
+ return PyFloat_FromDouble(v);
}
PyObject *
PLyInt_FromString(const char *src)
{
- long v;
- char *eptr;
+ long v;
+ char *eptr;
- enter();
+ enter();
- errno = 0;
- v = strtol(src, &eptr, 0);
- if ((*eptr != '\0') || (errno))
- return NULL;
- return PyInt_FromLong(v);
+ errno = 0;
+ v = strtol(src, &eptr, 0);
+ if ((*eptr != '\0') || (errno))
+ return NULL;
+ return PyInt_FromLong(v);
}
PyObject *
PLyLong_FromString(const char *src)
{
- return PyLong_FromString((char *)src,NULL,0);
+ return PyLong_FromString((char *) src, NULL, 0);
}
PyObject *
PLyString_FromString(const char *src)
{
- return PyString_FromString(src);
+ return PyString_FromString(src);
}
PyObject *
-PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
+PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
{
- DECLARE_EXC();
- PyObject *volatile dict;
- int i;
+ DECLARE_EXC();
+ PyObject *volatile dict;
+ int i;
- enter();
+ enter();
- if (info->is_rel != 1)
- elog(FATAL, "plpython: PLyTypeInfo structure describes a datum.");
+ if (info->is_rel != 1)
+ elog(FATAL, "plpython: PLyTypeInfo structure describes a datum.");
- dict = PyDict_New();
- if (dict == NULL)
- PLy_elog(ERROR, "Unable to create tuple dictionary.");
+ dict = PyDict_New();
+ if (dict == NULL)
+ PLy_elog(ERROR, "Unable to create tuple dictionary.");
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
- Py_DECREF(dict);
-
- RERAISE_EXC();
- }
-
- for (i = 0; i < info->in.r.natts; i++)
- {
- char *key, *vsrc;
- Datum vattr, vdat;
- bool is_null;
- PyObject *value;
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+ Py_DECREF(dict);
- key = NameStr(desc->attrs[i]->attname);
- vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
+ RERAISE_EXC();
+ }
- if ((is_null) || (info->in.r.atts[i].func == NULL))
- PyDict_SetItemString(dict, key, Py_None);
- else
+ for (i = 0; i < info->in.r.natts; i++)
{
- vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
- vattr,
- ObjectIdGetDatum(info->in.r.atts[i].typelem),
- Int32GetDatum(desc->attrs[i]->atttypmod));
- vsrc = DatumGetCString(vdat);
-
- /* no exceptions allowed
- */
- value = info->in.r.atts[i].func (vsrc);
- pfree(vsrc);
- PyDict_SetItemString(dict, key, value);
- Py_DECREF(value);
+ char *key,
+ *vsrc;
+ Datum vattr,
+ vdat;
+ bool is_null;
+ PyObject *value;
+
+ key = NameStr(desc->attrs[i]->attname);
+ vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
+
+ if ((is_null) || (info->in.r.atts[i].func == NULL))
+ PyDict_SetItemString(dict, key, Py_None);
+ else
+ {
+ vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
+ vattr,
+ ObjectIdGetDatum(info->in.r.atts[i].typelem),
+ Int32GetDatum(desc->attrs[i]->atttypmod));
+ vsrc = DatumGetCString(vdat);
+
+ /*
+ * no exceptions allowed
+ */
+ value = info->in.r.atts[i].func(vsrc);
+ pfree(vsrc);
+ PyDict_SetItemString(dict, key, value);
+ Py_DECREF(value);
+ }
}
- }
-
- RESTORE_EXC();
- return dict;
+ RESTORE_EXC();
+
+ return dict;
}
/* initialization, some python variables function declared here
@@ -1572,11 +1635,11 @@ static PyObject *PLy_result_getattr(PyObject *, char *);
static PyObject *PLy_result_fetch(PyObject *, PyObject *);
static PyObject *PLy_result_nrows(PyObject *, PyObject *);
static PyObject *PLy_result_status(PyObject *, PyObject *);
-static int PLy_result_length(PyObject *);
+static int PLy_result_length(PyObject *);
static PyObject *PLy_result_item(PyObject *, int);
static PyObject *PLy_result_slice(PyObject *, int, int);
-static int PLy_result_ass_item(PyObject *, int, PyObject *);
-static int PLy_result_ass_slice(PyObject *, int, int, PyObject *);
+static int PLy_result_ass_item(PyObject *, int, PyObject *);
+static int PLy_result_ass_slice(PyObject *, int, int, PyObject *);
static PyObject *PLy_spi_prepare(PyObject *, PyObject *);
@@ -1588,100 +1651,107 @@ static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int);
PyTypeObject PLy_PlanType = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "PLyPlan", /*tp_name*/
- sizeof(PLyPlanObject), /*tp_size*/
- 0, /*tp_itemsize*/
- /* methods
- */
- (destructor) PLy_plan_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc)PLy_plan_getattr, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- 0, /*tp_xxx4*/
- PLy_plan_doc, /*tp_doc*/
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "PLyPlan", /* tp_name */
+ sizeof(PLyPlanObject), /* tp_size */
+ 0, /* tp_itemsize */
+
+ /*
+ * methods
+ */
+ (destructor) PLy_plan_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) PLy_plan_getattr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ 0, /* tp_xxx4 */
+ PLy_plan_doc, /* tp_doc */
};
PyMethodDef PLy_plan_methods[] = {
- { "status", (PyCFunction) PLy_plan_status, METH_VARARGS, NULL },
- { NULL, NULL, 0, NULL }
+ {"status", (PyCFunction) PLy_plan_status, METH_VARARGS, NULL},
+ {NULL, NULL, 0, NULL}
};
PySequenceMethods PLy_result_as_sequence = {
- (inquiry) PLy_result_length, /* sq_length */
- (binaryfunc) 0, /* sq_concat */
- (intargfunc) 0, /* sq_repeat */
- (intargfunc) PLy_result_item, /* sq_item */
- (intintargfunc) PLy_result_slice, /* sq_slice */
- (intobjargproc) PLy_result_ass_item, /* sq_ass_item */
- (intintobjargproc) PLy_result_ass_slice, /* sq_ass_slice */
+ (inquiry) PLy_result_length,/* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) PLy_result_item, /* sq_item */
+ (intintargfunc) PLy_result_slice, /* sq_slice */
+ (intobjargproc) PLy_result_ass_item, /* sq_ass_item */
+ (intintobjargproc) PLy_result_ass_slice, /* sq_ass_slice */
};
PyTypeObject PLy_ResultType = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "PLyResult", /*tp_name*/
- sizeof(PLyResultObject), /*tp_size*/
- 0, /*tp_itemsize*/
- /* methods
- */
- (destructor) PLy_result_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc) PLy_result_getattr, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- &PLy_result_as_sequence, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- 0, /*tp_xxx4*/
- PLy_result_doc, /*tp_doc*/
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "PLyResult", /* tp_name */
+ sizeof(PLyResultObject), /* tp_size */
+ 0, /* tp_itemsize */
+
+ /*
+ * methods
+ */
+ (destructor) PLy_result_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) PLy_result_getattr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ &PLy_result_as_sequence, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ 0, /* tp_xxx4 */
+ PLy_result_doc, /* tp_doc */
};
PyMethodDef PLy_result_methods[] = {
- { "fetch", (PyCFunction) PLy_result_fetch, METH_VARARGS, NULL,},
- { "nrows", (PyCFunction) PLy_result_nrows, METH_VARARGS, NULL },
- { "status", (PyCFunction) PLy_result_status, METH_VARARGS, NULL },
- { NULL, NULL, 0, NULL }
+ {"fetch", (PyCFunction) PLy_result_fetch, METH_VARARGS, NULL,},
+ {"nrows", (PyCFunction) PLy_result_nrows, METH_VARARGS, NULL},
+ {"status", (PyCFunction) PLy_result_status, METH_VARARGS, NULL},
+ {NULL, NULL, 0, NULL}
};
static PyMethodDef PLy_methods[] = {
- /* logging methods
- */
- { "debug", PLy_debug, METH_VARARGS, NULL },
- { "error", PLy_error, METH_VARARGS, NULL },
- { "fatal", PLy_fatal, METH_VARARGS, NULL },
- { "notice", PLy_notice, METH_VARARGS, NULL },
-
- /* create a stored plan
- */
- { "prepare", PLy_spi_prepare, METH_VARARGS, NULL },
-
- /* execute a plan or query
- */
- { "execute", PLy_spi_execute, METH_VARARGS, NULL },
-
- { NULL, NULL, 0, NULL }
+ /*
+ * logging methods
+ */
+ {"debug", PLy_debug, METH_VARARGS, NULL},
+ {"error", PLy_error, METH_VARARGS, NULL},
+ {"fatal", PLy_fatal, METH_VARARGS, NULL},
+ {"notice", PLy_notice, METH_VARARGS, NULL},
+
+ /*
+ * create a stored plan
+ */
+ {"prepare", PLy_spi_prepare, METH_VARARGS, NULL},
+
+ /*
+ * execute a plan or query
+ */
+ {"execute", PLy_spi_execute, METH_VARARGS, NULL},
+
+ {NULL, NULL, 0, NULL}
};
@@ -1690,72 +1760,72 @@ static PyMethodDef PLy_methods[] = {
PyObject *
PLy_plan_new(void)
{
- PLyPlanObject *ob;
-
- enter();
+ PLyPlanObject *ob;
- if ((ob = PyObject_NEW(PLyPlanObject, &PLy_PlanType)) == NULL)
- return NULL;
+ enter();
- ob->plan = NULL;
- ob->nargs = 0;
- ob->types = NULL;
- ob->args = NULL;
+ if ((ob = PyObject_NEW(PLyPlanObject, &PLy_PlanType)) == NULL)
+ return NULL;
- return (PyObject *) ob;
+ ob->plan = NULL;
+ ob->nargs = 0;
+ ob->types = NULL;
+ ob->args = NULL;
+
+ return (PyObject *) ob;
}
void
-PLy_plan_dealloc(PyObject *arg)
+PLy_plan_dealloc(PyObject * arg)
{
- PLyPlanObject *ob = (PLyPlanObject *) arg;
+ PLyPlanObject *ob = (PLyPlanObject *) arg;
- enter();
+ enter();
- if (ob->plan)
- {
- /* free the plan...
- * pfree(ob->plan);
- *
- * FIXME -- leaks saved plan on object destruction. can
- * this be avoided?
- */
- }
- if (ob->types)
- PLy_free(ob->types);
- if (ob->args)
- {
- int i;
+ if (ob->plan)
+ {
+ /*
+ * free the plan... pfree(ob->plan);
+ *
+ * FIXME -- leaks saved plan on object destruction. can this be
+ * avoided?
+ */
+ }
+ if (ob->types)
+ PLy_free(ob->types);
+ if (ob->args)
+ {
+ int i;
- for (i = 0; i < ob->nargs; i++)
- PLy_typeinfo_dealloc(&ob->args[i]);
- PLy_free(ob->args);
- }
+ for (i = 0; i < ob->nargs; i++)
+ PLy_typeinfo_dealloc(&ob->args[i]);
+ PLy_free(ob->args);
+ }
- PyMem_DEL(arg);
+ PyMem_DEL(arg);
- leave();
+ leave();
}
PyObject *
-PLy_plan_getattr(PyObject *self, char *name)
+PLy_plan_getattr(PyObject * self, char *name)
{
- return Py_FindMethod(PLy_plan_methods, self, name);
+ return Py_FindMethod(PLy_plan_methods, self, name);
}
PyObject *
-PLy_plan_status(PyObject *self, PyObject *args)
+PLy_plan_status(PyObject * self, PyObject * args)
{
- if (PyArg_ParseTuple(args, ""))
- {
- Py_INCREF(Py_True);
- return Py_True;
- /* return PyInt_FromLong(self->status); */
- }
- PyErr_SetString(PLy_exc_error, "plan.status() takes no arguments");
- return NULL;
+ if (PyArg_ParseTuple(args, ""))
+ {
+ Py_INCREF(Py_True);
+ return Py_True;
+ /* return PyInt_FromLong(self->status); */
+ }
+ PyErr_SetString(PLy_exc_error, "plan.status() takes no arguments");
+ return NULL;
}
@@ -1766,626 +1836,649 @@ PLy_plan_status(PyObject *self, PyObject *args)
static PyObject *
PLy_result_new(void)
{
- PLyResultObject *ob;
-
- enter();
+ PLyResultObject *ob;
+
+ enter();
- if ((ob = PyObject_NEW(PLyResultObject, &PLy_ResultType)) == NULL)
- return NULL;
+ if ((ob = PyObject_NEW(PLyResultObject, &PLy_ResultType)) == NULL)
+ return NULL;
- /* ob->tuples = NULL; */
+ /* ob->tuples = NULL; */
- Py_INCREF(Py_None);
- ob->status = Py_None;
- ob->nrows = PyInt_FromLong(-1);
- ob->rows = PyList_New(0);
+ Py_INCREF(Py_None);
+ ob->status = Py_None;
+ ob->nrows = PyInt_FromLong(-1);
+ ob->rows = PyList_New(0);
- return (PyObject *) ob;
+ return (PyObject *) ob;
}
static void
-PLy_result_dealloc(PyObject *arg)
+PLy_result_dealloc(PyObject * arg)
{
- PLyResultObject *ob = (PLyResultObject *) arg;
+ PLyResultObject *ob = (PLyResultObject *) arg;
- enter();
+ enter();
- Py_XDECREF(ob->nrows);
- Py_XDECREF(ob->rows);
- Py_XDECREF(ob->status);
+ Py_XDECREF(ob->nrows);
+ Py_XDECREF(ob->rows);
+ Py_XDECREF(ob->status);
- PyMem_DEL(ob);
+ PyMem_DEL(ob);
}
static PyObject *
-PLy_result_getattr(PyObject *self, char *attr)
+PLy_result_getattr(PyObject * self, char *attr)
{
- return NULL;
+ return NULL;
}
static PyObject *
-PLy_result_fetch(PyObject *self, PyObject *args)
+PLy_result_fetch(PyObject * self, PyObject * args)
{
- return NULL;
+ return NULL;
}
static PyObject *
-PLy_result_nrows(PyObject *self, PyObject *args)
+PLy_result_nrows(PyObject * self, PyObject * args)
{
- PLyResultObject *ob = (PLyResultObject *) self;
- Py_INCREF(ob->nrows);
- return ob->nrows;
+ PLyResultObject *ob = (PLyResultObject *) self;
+
+ Py_INCREF(ob->nrows);
+ return ob->nrows;
}
static PyObject *
-PLy_result_status(PyObject *self, PyObject *args)
+PLy_result_status(PyObject * self, PyObject * args)
{
- PLyResultObject *ob = (PLyResultObject *) self;
- Py_INCREF(ob->status);
- return ob->status;
+ PLyResultObject *ob = (PLyResultObject *) self;
+
+ Py_INCREF(ob->status);
+ return ob->status;
}
int
-PLy_result_length(PyObject *arg)
+PLy_result_length(PyObject * arg)
{
- PLyResultObject *ob = (PLyResultObject *) arg;
- return PyList_Size(ob->rows);
+ PLyResultObject *ob = (PLyResultObject *) arg;
+
+ return PyList_Size(ob->rows);
}
PyObject *
-PLy_result_item(PyObject *arg, int idx)
+PLy_result_item(PyObject * arg, int idx)
{
- PyObject *rv;
- PLyResultObject *ob = (PLyResultObject *) arg;
+ PyObject *rv;
+ PLyResultObject *ob = (PLyResultObject *) arg;
- rv = PyList_GetItem(ob->rows, idx);
- if (rv != NULL)
- Py_INCREF(rv);
- return rv;
+ rv = PyList_GetItem(ob->rows, idx);
+ if (rv != NULL)
+ Py_INCREF(rv);
+ return rv;
}
int
-PLy_result_ass_item(PyObject *arg, int idx, PyObject *item)
+PLy_result_ass_item(PyObject * arg, int idx, PyObject * item)
{
- int rv;
- PLyResultObject *ob = (PLyResultObject *) arg;
+ int rv;
+ PLyResultObject *ob = (PLyResultObject *) arg;
- Py_INCREF(item);
- rv = PyList_SetItem(ob->rows, idx, item);
- return rv;
+ Py_INCREF(item);
+ rv = PyList_SetItem(ob->rows, idx, item);
+ return rv;
}
PyObject *
-PLy_result_slice(PyObject *arg, int lidx, int hidx)
+PLy_result_slice(PyObject * arg, int lidx, int hidx)
{
- PyObject *rv;
- PLyResultObject *ob = (PLyResultObject *) arg;
-
- rv = PyList_GetSlice(ob->rows, lidx, hidx);
- if (rv == NULL)
- return NULL;
- Py_INCREF(rv);
- return rv;
+ PyObject *rv;
+ PLyResultObject *ob = (PLyResultObject *) arg;
+
+ rv = PyList_GetSlice(ob->rows, lidx, hidx);
+ if (rv == NULL)
+ return NULL;
+ Py_INCREF(rv);
+ return rv;
}
int
-PLy_result_ass_slice(PyObject *arg, int lidx, int hidx, PyObject *slice)
+PLy_result_ass_slice(PyObject * arg, int lidx, int hidx, PyObject * slice)
{
- int rv;
- PLyResultObject *ob = (PLyResultObject *) arg;
-
- rv = PyList_SetSlice(ob->rows, lidx, hidx, slice);
- return rv;
+ int rv;
+ PLyResultObject *ob = (PLyResultObject *) arg;
+
+ rv = PyList_SetSlice(ob->rows, lidx, hidx, slice);
+ return rv;
}
/* SPI interface
*/
PyObject *
-PLy_spi_prepare(PyObject *self, PyObject *args)
-{
- DECLARE_EXC();
- PLyPlanObject *plan;
- PyObject *list = NULL;
- PyObject * volatile optr = NULL;
- char *query;
-
- enter();
-
- if (!PyArg_ParseTuple(args, "s|O", &query, &list))
- {
- PyErr_SetString(PLy_exc_spi_error,
- "Invalid arguments for plpy.prepare()");
- return NULL;
- }
-
- if ((list) && (!PySequence_Check(list)))
- {
- PyErr_SetString(PLy_exc_spi_error,
- "Second argument in plpy.prepare() must be a sequence");
- return NULL;
- }
-
-
- if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
- return NULL;
-
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
- Py_DECREF(plan);
- Py_XDECREF(optr);
- if (!PyErr_Occurred ())
- PyErr_SetString(PLy_exc_spi_error,
- "Unknown error in PLy_spi_prepare.");
- return NULL;
- }
-
- if (list != NULL)
- {
- int nargs, i;
-
-
- nargs = PySequence_Length(list);
- if (nargs > 0)
- {
- plan->nargs = nargs;
- plan->types = PLy_malloc(sizeof(Oid) * nargs);
- plan->values = PLy_malloc(sizeof(Datum) * nargs);
- plan->args = PLy_malloc(sizeof(PLyTypeInfo) * nargs);
-
- /* the other loop might throw an exception, if PLyTypeInfo
- * member isn't properly initialized the Py_DECREF(plan)
- * will go boom
- */
- for (i = 0; i < nargs; i++)
- {
- PLy_typeinfo_init(&plan->args[i]);
- plan->values[i] = (Datum) NULL;
- }
-
- for (i = 0; i < nargs; i++)
- {
- char *sptr;
- HeapTuple typeTup;
- Form_pg_type typeStruct;
-
- optr = PySequence_GetItem(list, i);
- if (!PyString_Check(optr))
- {
- PyErr_SetString(PLy_exc_spi_error,
- "Type names must be strings.");
- RAISE_EXC(1);
- }
- sptr = PyString_AsString(optr);
- typeTup = SearchSysCache(TYPENAME, PointerGetDatum(sptr),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTup))
- {
- PLy_exception_set(PLy_exc_spi_error,
- "Cache lookup for type `%s' failed.",
- sptr);
- RAISE_EXC(1);
- }
+PLy_spi_prepare(PyObject * self, PyObject * args)
+{
+ DECLARE_EXC();
+ PLyPlanObject *plan;
+ PyObject *list = NULL;
+ PyObject *volatile optr = NULL;
+ char *query;
- Py_DECREF(optr);
- optr = NULL; /* this is important */
+ enter();
- plan->types[i] = typeTup->t_data->t_oid;
- typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
- if (typeStruct->typrelid == InvalidOid)
- PLy_output_datum_func(&plan->args[i], typeStruct);
- else
+ if (!PyArg_ParseTuple(args, "s|O", &query, &list))
+ {
+ PyErr_SetString(PLy_exc_spi_error,
+ "Invalid arguments for plpy.prepare()");
+ return NULL;
+ }
+
+ if ((list) && (!PySequence_Check(list)))
+ {
+ PyErr_SetString(PLy_exc_spi_error,
+ "Second argument in plpy.prepare() must be a sequence");
+ return NULL;
+ }
+
+
+ if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
+ return NULL;
+
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+ Py_DECREF(plan);
+ Py_XDECREF(optr);
+ if (!PyErr_Occurred())
+ PyErr_SetString(PLy_exc_spi_error,
+ "Unknown error in PLy_spi_prepare.");
+ return NULL;
+ }
+
+ if (list != NULL)
+ {
+ int nargs,
+ i;
+
+
+ nargs = PySequence_Length(list);
+ if (nargs > 0)
{
- PyErr_SetString(PLy_exc_spi_error,
- "tuples not handled in plpy.prepare, yet.");
- RAISE_EXC(1);
+ plan->nargs = nargs;
+ plan->types = PLy_malloc(sizeof(Oid) * nargs);
+ plan->values = PLy_malloc(sizeof(Datum) * nargs);
+ plan->args = PLy_malloc(sizeof(PLyTypeInfo) * nargs);
+
+ /*
+ * the other loop might throw an exception, if PLyTypeInfo
+ * member isn't properly initialized the Py_DECREF(plan) will
+ * go boom
+ */
+ for (i = 0; i < nargs; i++)
+ {
+ PLy_typeinfo_init(&plan->args[i]);
+ plan->values[i] = (Datum) NULL;
+ }
+
+ for (i = 0; i < nargs; i++)
+ {
+ char *sptr;
+ HeapTuple typeTup;
+ Form_pg_type typeStruct;
+
+ optr = PySequence_GetItem(list, i);
+ if (!PyString_Check(optr))
+ {
+ PyErr_SetString(PLy_exc_spi_error,
+ "Type names must be strings.");
+ RAISE_EXC(1);
+ }
+ sptr = PyString_AsString(optr);
+ typeTup = SearchSysCache(TYPENAME, PointerGetDatum(sptr),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTup))
+ {
+ PLy_exception_set(PLy_exc_spi_error,
+ "Cache lookup for type `%s' failed.",
+ sptr);
+ RAISE_EXC(1);
+ }
+
+ Py_DECREF(optr);
+ optr = NULL; /* this is important */
+
+ plan->types[i] = typeTup->t_data->t_oid;
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+ if (typeStruct->typrelid == InvalidOid)
+ PLy_output_datum_func(&plan->args[i], typeStruct);
+ else
+ {
+ PyErr_SetString(PLy_exc_spi_error,
+ "tuples not handled in plpy.prepare, yet.");
+ RAISE_EXC(1);
+ }
+ ReleaseSysCache(typeTup);
+ }
}
- ReleaseSysCache(typeTup);
- }
}
- }
- plan->plan = SPI_prepare(query, plan->nargs, plan->types);
- if (plan->plan == NULL)
- {
- PLy_exception_set(PLy_exc_spi_error,
- "Unable to prepare plan. SPI_prepare failed -- %s.",
- PLy_spi_error_string(SPI_result));
- RAISE_EXC(1);
- }
+ plan->plan = SPI_prepare(query, plan->nargs, plan->types);
+ if (plan->plan == NULL)
+ {
+ PLy_exception_set(PLy_exc_spi_error,
+ "Unable to prepare plan. SPI_prepare failed -- %s.",
+ PLy_spi_error_string(SPI_result));
+ RAISE_EXC(1);
+ }
- plan->plan = SPI_saveplan(plan->plan);
- if (plan->plan == NULL)
- {
- PLy_exception_set(PLy_exc_spi_error,
- "Unable to save plan. SPI_saveplan failed -- %s.",
- PLy_spi_error_string(SPI_result));
- RAISE_EXC(1);
- }
+ plan->plan = SPI_saveplan(plan->plan);
+ if (plan->plan == NULL)
+ {
+ PLy_exception_set(PLy_exc_spi_error,
+ "Unable to save plan. SPI_saveplan failed -- %s.",
+ PLy_spi_error_string(SPI_result));
+ RAISE_EXC(1);
+ }
- RESTORE_EXC();
+ RESTORE_EXC();
- return (PyObject *) plan;
+ return (PyObject *) plan;
}
/* execute(query="select * from foo", limit=5)
* execute(plan=plan, values=(foo, bar), limit=5)
*/
PyObject *
-PLy_spi_execute(PyObject *self, PyObject *args)
+PLy_spi_execute(PyObject * self, PyObject * args)
{
- char *query;
- PyObject *plan;
- PyObject *list = NULL;
- int limit = 0;
+ char *query;
+ PyObject *plan;
+ PyObject *list = NULL;
+ int limit = 0;
- enter();
+ enter();
#if 0
- /* there should - hahaha - be an python exception set so just
- * return NULL. FIXME -- is this needed?
- */
- if (PLy_restart_in_progress)
- return NULL;
+
+ /*
+ * there should - hahaha - be an python exception set so just return
+ * NULL. FIXME -- is this needed?
+ */
+ if (PLy_restart_in_progress)
+ return NULL;
#endif
- if (PyArg_ParseTuple(args, "s|i", &query, &limit))
- return PLy_spi_execute_query(query, limit);
+ if (PyArg_ParseTuple(args, "s|i", &query, &limit))
+ return PLy_spi_execute_query(query, limit);
- PyErr_Clear();
+ PyErr_Clear();
+
+ if ((PyArg_ParseTuple(args, "O|Oi", &plan, &list, &limit)) &&
+ (is_PLyPlanObject(plan)))
+ {
+ PyObject *rv = PLy_spi_execute_plan(plan, list, limit);
- if ((PyArg_ParseTuple(args, "O|Oi", &plan, &list, &limit)) &&
- (is_PLyPlanObject(plan)))
- {
- PyObject *rv = PLy_spi_execute_plan(plan, list, limit);
- return rv;
- }
+ return rv;
+ }
- PyErr_SetString(PLy_exc_error, "Expected a query or plan.");
- return NULL;
+ PyErr_SetString(PLy_exc_error, "Expected a query or plan.");
+ return NULL;
}
PyObject *
-PLy_spi_execute_plan(PyObject *ob, PyObject *list, int limit)
+PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
{
- DECLARE_EXC();
- volatile int nargs;
- int i, rv;
- PLyPlanObject *plan;
+ DECLARE_EXC();
+ volatile int nargs;
+ int i,
+ rv;
+ PLyPlanObject *plan;
- enter();
+ enter();
- if (list != NULL)
- {
- if ((!PySequence_Check(list)) || (PyString_Check(list)))
+ if (list != NULL)
{
- char *msg = "plpy.execute() takes a sequence as its second argument";
- PyErr_SetString(PLy_exc_spi_error, msg);
- return NULL;
- }
- nargs = PySequence_Length(list);
- }
- else
- nargs = 0;
+ if ((!PySequence_Check(list)) || (PyString_Check(list)))
+ {
+ char *msg = "plpy.execute() takes a sequence as its second argument";
- plan = (PLyPlanObject *) ob;
+ PyErr_SetString(PLy_exc_spi_error, msg);
+ return NULL;
+ }
+ nargs = PySequence_Length(list);
+ }
+ else
+ nargs = 0;
- if (nargs != plan->nargs)
- {
- char *sv;
+ plan = (PLyPlanObject *) ob;
- PyObject *so = PyObject_Str(list);
- sv = PyString_AsString(so);
- PLy_exception_set(PLy_exc_spi_error,
- "Expected sequence of %d arguments, got %d. %s",
- plan->nargs, nargs, sv);
- Py_DECREF(so);
+ if (nargs != plan->nargs)
+ {
+ char *sv;
- return NULL;
- }
+ PyObject *so = PyObject_Str(list);
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
+ sv = PyString_AsString(so);
+ PLy_exception_set(PLy_exc_spi_error,
+ "Expected sequence of %d arguments, got %d. %s",
+ plan->nargs, nargs, sv);
+ Py_DECREF(so);
- /* cleanup plan->values array
- */
- for (i = 0; i < nargs; i++)
- {
- if (!plan->args[i].out.d.typbyval &&
- (plan->values[i] != (Datum) NULL))
- {
- pfree(DatumGetPointer(plan->values[i]));
- plan->values[i] = (Datum) NULL;
- }
+ return NULL;
}
- if (!PyErr_Occurred())
- PyErr_SetString(PLy_exc_error,
- "Unknown error in PLy_spi_execute_plan");
- return NULL;
- }
-
- if (nargs)
- {
- for (i = 0; i < nargs; i++)
+ SAVE_EXC();
+ if (TRAP_EXC())
{
- PyObject *elem, *so;
- char *sv;
+ RESTORE_EXC();
- elem = PySequence_GetItem(list, i);
- so = PyObject_Str(elem);
- sv = PyString_AsString(so);
+ /*
+ * cleanup plan->values array
+ */
+ for (i = 0; i < nargs; i++)
+ {
+ if (!plan->args[i].out.d.typbyval &&
+ (plan->values[i] != (Datum) NULL))
+ {
+ pfree(DatumGetPointer(plan->values[i]));
+ plan->values[i] = (Datum) NULL;
+ }
+ }
- /* FIXME -- if this can elog, we have leak
- */
- plan->values[i] = FunctionCall3(&(plan->args[i].out.d.typfunc),
- CStringGetDatum(sv),
- ObjectIdGetDatum(plan->args[i].out.d.typelem),
- Int32GetDatum(-1));
+ if (!PyErr_Occurred())
+ PyErr_SetString(PLy_exc_error,
+ "Unknown error in PLy_spi_execute_plan");
+ return NULL;
+ }
- Py_DECREF(so);
- Py_DECREF(elem);
+ if (nargs)
+ {
+ for (i = 0; i < nargs; i++)
+ {
+ PyObject *elem,
+ *so;
+ char *sv;
+
+ elem = PySequence_GetItem(list, i);
+ so = PyObject_Str(elem);
+ sv = PyString_AsString(so);
+
+ /*
+ * FIXME -- if this can elog, we have leak
+ */
+ plan->values[i] = FunctionCall3(&(plan->args[i].out.d.typfunc),
+ CStringGetDatum(sv),
+ ObjectIdGetDatum(plan->args[i].out.d.typelem),
+ Int32GetDatum(-1));
+
+ Py_DECREF(so);
+ Py_DECREF(elem);
+ }
}
- }
- rv = SPI_execp(plan->plan, plan->values, NULL, limit);
- RESTORE_EXC();
+ rv = SPI_execp(plan->plan, plan->values, NULL, limit);
+ RESTORE_EXC();
- for (i = 0; i < nargs; i++)
- {
- if (!plan->args[i].out.d.typbyval &&
- (plan->values[i] != (Datum) NULL))
+ for (i = 0; i < nargs; i++)
{
- pfree(DatumGetPointer(plan->values[i]));
- plan->values[i] = (Datum) NULL;
+ if (!plan->args[i].out.d.typbyval &&
+ (plan->values[i] != (Datum) NULL))
+ {
+ pfree(DatumGetPointer(plan->values[i]));
+ plan->values[i] = (Datum) NULL;
+ }
}
- }
- if (rv < 0)
- {
- PLy_exception_set(PLy_exc_spi_error,
- "Unable to execute plan. SPI_execp failed -- %s",
- PLy_spi_error_string(rv));
- return NULL;
- }
+ if (rv < 0)
+ {
+ PLy_exception_set(PLy_exc_spi_error,
+ "Unable to execute plan. SPI_execp failed -- %s",
+ PLy_spi_error_string(rv));
+ return NULL;
+ }
- return PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv);
+ return PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv);
}
PyObject *
PLy_spi_execute_query(char *query, int limit)
{
- DECLARE_EXC();
- int rv;
+ DECLARE_EXC();
+ int rv;
+
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
+ if ((!PLy_restart_in_progress) && (!PyErr_Occurred()))
+ PyErr_SetString(PLy_exc_spi_error,
+ "Unknown error in PLy_spi_execute_query.");
+ return NULL;
+ }
- if ((!PLy_restart_in_progress) && (!PyErr_Occurred()))
- PyErr_SetString(PLy_exc_spi_error,
- "Unknown error in PLy_spi_execute_query.");
- return NULL;
- }
-
- rv = SPI_exec(query, limit);
- RESTORE_EXC();
+ rv = SPI_exec(query, limit);
+ RESTORE_EXC();
- if (rv < 0)
- {
- PLy_exception_set(PLy_exc_spi_error,
- "Unable to execute query. SPI_exec failed -- %s",
- PLy_spi_error_string(rv));
- return NULL;
- }
+ if (rv < 0)
+ {
+ PLy_exception_set(PLy_exc_spi_error,
+ "Unable to execute query. SPI_exec failed -- %s",
+ PLy_spi_error_string(rv));
+ return NULL;
+ }
- return PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv);
+ return PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv);
}
PyObject *
PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
{
- PLyResultObject *result;
-
- enter();
-
- result = (PLyResultObject *) PLy_result_new();
- Py_DECREF(result->status);
- result->status = PyInt_FromLong(status);
+ PLyResultObject *result;
- if (status == SPI_OK_UTILITY)
- {
- Py_DECREF(result->nrows);
- result->nrows = PyInt_FromLong(0);
- }
- else if (status != SPI_OK_SELECT)
- {
- Py_DECREF(result->nrows);
- result->nrows = PyInt_FromLong(rows);
- }
- else
- {
- DECLARE_EXC();
- PLyTypeInfo args;
- int i;
+ enter();
- PLy_typeinfo_init(&args);
- Py_DECREF(result->nrows);
- result->nrows = PyInt_FromLong(rows);
+ result = (PLyResultObject *) PLy_result_new();
+ Py_DECREF(result->status);
+ result->status = PyInt_FromLong(status);
- SAVE_EXC();
- if (TRAP_EXC())
+ if (status == SPI_OK_UTILITY)
{
- RESTORE_EXC();
-
- if (!PyErr_Occurred())
- PyErr_SetString(PLy_exc_error,
- "Unknown error in PLy_spi_execute_fetch_result");
- Py_DECREF(result);
- PLy_typeinfo_dealloc(&args);
- return NULL;
+ Py_DECREF(result->nrows);
+ result->nrows = PyInt_FromLong(0);
+ }
+ else if (status != SPI_OK_SELECT)
+ {
+ Py_DECREF(result->nrows);
+ result->nrows = PyInt_FromLong(rows);
}
-
- if (rows)
+ else
{
- Py_DECREF(result->rows);
- result->rows = PyList_New(rows);
+ DECLARE_EXC();
+ PLyTypeInfo args;
+ int i;
+
+ PLy_typeinfo_init(&args);
+ Py_DECREF(result->nrows);
+ result->nrows = PyInt_FromLong(rows);
+
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+
+ if (!PyErr_Occurred())
+ PyErr_SetString(PLy_exc_error,
+ "Unknown error in PLy_spi_execute_fetch_result");
+ Py_DECREF(result);
+ PLy_typeinfo_dealloc(&args);
+ return NULL;
+ }
- PLy_input_tuple_funcs(&args, tuptable->tupdesc);
- for (i = 0; i < rows; i++)
- {
- PyObject *row = PLyDict_FromTuple(&args, tuptable->vals[i],
- tuptable->tupdesc);
- PyList_SetItem(result->rows, i, row);
- }
- PLy_typeinfo_dealloc(&args);
+ if (rows)
+ {
+ Py_DECREF(result->rows);
+ result->rows = PyList_New(rows);
+
+ PLy_input_tuple_funcs(&args, tuptable->tupdesc);
+ for (i = 0; i < rows; i++)
+ {
+ PyObject *row = PLyDict_FromTuple(&args, tuptable->vals[i],
+ tuptable->tupdesc);
+
+ PyList_SetItem(result->rows, i, row);
+ }
+ PLy_typeinfo_dealloc(&args);
+ }
+ RESTORE_EXC();
}
- RESTORE_EXC();
- }
- return (PyObject *) result;
+ return (PyObject *) result;
}
const char *
PLy_spi_error_string(int code)
{
- switch (code)
- {
- case SPI_ERROR_TYPUNKNOWN:
- return "SPI_ERROR_TYPUNKNOWN";
- case SPI_ERROR_NOOUTFUNC:
- return "SPI_ERROR_NOOUTFUNC";
- case SPI_ERROR_NOATTRIBUTE:
- return "SPI_ERROR_NOATTRIBUTE";
- case SPI_ERROR_TRANSACTION:
- return "SPI_ERROR_TRANSACTION";
- case SPI_ERROR_PARAM:
- return "SPI_ERROR_PARAM";
- case SPI_ERROR_ARGUMENT:
- return "SPI_ERROR_ARGUMENT";
- case SPI_ERROR_CURSOR:
- return "SPI_ERROR_CURSOR";
- case SPI_ERROR_UNCONNECTED:
- return "SPI_ERROR_UNCONNECTED";
- case SPI_ERROR_OPUNKNOWN:
- return "SPI_ERROR_OPUNKNOWN";
- case SPI_ERROR_COPY:
- return "SPI_ERROR_COPY";
- case SPI_ERROR_CONNECT:
- return "SPI_ERROR_CONNECT";
- }
- return "Unknown or Invalid code";
+ switch (code)
+ {
+ case SPI_ERROR_TYPUNKNOWN:
+ return "SPI_ERROR_TYPUNKNOWN";
+ case SPI_ERROR_NOOUTFUNC:
+ return "SPI_ERROR_NOOUTFUNC";
+ case SPI_ERROR_NOATTRIBUTE:
+ return "SPI_ERROR_NOATTRIBUTE";
+ case SPI_ERROR_TRANSACTION:
+ return "SPI_ERROR_TRANSACTION";
+ case SPI_ERROR_PARAM:
+ return "SPI_ERROR_PARAM";
+ case SPI_ERROR_ARGUMENT:
+ return "SPI_ERROR_ARGUMENT";
+ case SPI_ERROR_CURSOR:
+ return "SPI_ERROR_CURSOR";
+ case SPI_ERROR_UNCONNECTED:
+ return "SPI_ERROR_UNCONNECTED";
+ case SPI_ERROR_OPUNKNOWN:
+ return "SPI_ERROR_OPUNKNOWN";
+ case SPI_ERROR_COPY:
+ return "SPI_ERROR_COPY";
+ case SPI_ERROR_CONNECT:
+ return "SPI_ERROR_CONNECT";
+ }
+ return "Unknown or Invalid code";
}
/* language handler and interpreter initialization
*/
-void PLy_init_all(void)
+void
+PLy_init_all(void)
{
- static volatile int init_active = 0;
+ static volatile int init_active = 0;
- enter();
+ enter();
- if (init_active)
- elog(FATAL, "plpython: Initialization of language module failed.");
- init_active = 1;
+ if (init_active)
+ elog(FATAL, "plpython: Initialization of language module failed.");
+ init_active = 1;
- Py_Initialize();
- PLy_init_interp();
- PLy_init_plpy();
- PLy_init_safe_interp();
- if (PyErr_Occurred())
- PLy_elog(FATAL, "Untrapped error in initialization.");
- PLy_procedure_cache = PyDict_New();
- if (PLy_procedure_cache == NULL)
- PLy_elog(ERROR, "Unable to create procedure cache.");
+ Py_Initialize();
+ PLy_init_interp();
+ PLy_init_plpy();
+ PLy_init_safe_interp();
+ if (PyErr_Occurred())
+ PLy_elog(FATAL, "Untrapped error in initialization.");
+ PLy_procedure_cache = PyDict_New();
+ if (PLy_procedure_cache == NULL)
+ PLy_elog(ERROR, "Unable to create procedure cache.");
- PLy_first_call = 0;
+ PLy_first_call = 0;
- leave();
+ leave();
}
void
PLy_init_interp(void)
{
- PyObject *mainmod;
+ PyObject *mainmod;
- enter();
+ enter();
- mainmod = PyImport_AddModule("__main__");
- if ((mainmod == NULL) || (PyErr_Occurred()))
- PLy_elog(ERROR, "Unable to import '__main__' module.");
- Py_INCREF(mainmod);
- PLy_interp_globals = PyModule_GetDict(mainmod);
- Py_DECREF(mainmod);
- if ((PLy_interp_globals == NULL) || (PyErr_Occurred()))
- PLy_elog(ERROR, "Unable to initialize globals.");
+ mainmod = PyImport_AddModule("__main__");
+ if ((mainmod == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to import '__main__' module.");
+ Py_INCREF(mainmod);
+ PLy_interp_globals = PyModule_GetDict(mainmod);
+ Py_DECREF(mainmod);
+ if ((PLy_interp_globals == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to initialize globals.");
}
void
PLy_init_plpy(void)
{
- PyObject *main_mod, *main_dict, *plpy_mod;
- PyObject *plpy, *plpy_dict;
-
- enter();
-
- /* initialize plpy module
- */
- PLy_PlanType.ob_type = PLy_ResultType.ob_type = &PyType_Type;
- plpy = Py_InitModule("plpy", PLy_methods);
- plpy_dict = PyModule_GetDict(plpy);
-
- /* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
-
- PLy_exc_error = PyErr_NewException("plpy.Error", NULL, NULL);
- PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL);
- PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL);
- PyDict_SetItemString(plpy_dict, "Error", PLy_exc_error);
- PyDict_SetItemString(plpy_dict, "Fatal", PLy_exc_fatal);
- PyDict_SetItemString(plpy_dict, "SPIError", PLy_exc_spi_error);
-
- /* initialize main module, and add plpy
- */
- main_mod = PyImport_AddModule("__main__");
- main_dict = PyModule_GetDict(main_mod);
- plpy_mod = PyImport_AddModule("plpy");
- PyDict_SetItemString(main_dict, "plpy", plpy_mod);
- if (PyErr_Occurred ())
- elog(ERROR, "Unable to init plpy.");
+ PyObject *main_mod,
+ *main_dict,
+ *plpy_mod;
+ PyObject *plpy,
+ *plpy_dict;
+
+ enter();
+
+ /*
+ * initialize plpy module
+ */
+ PLy_PlanType.ob_type = PLy_ResultType.ob_type = &PyType_Type;
+ plpy = Py_InitModule("plpy", PLy_methods);
+ plpy_dict = PyModule_GetDict(plpy);
+
+ /* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
+
+ PLy_exc_error = PyErr_NewException("plpy.Error", NULL, NULL);
+ PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL);
+ PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL);
+ PyDict_SetItemString(plpy_dict, "Error", PLy_exc_error);
+ PyDict_SetItemString(plpy_dict, "Fatal", PLy_exc_fatal);
+ PyDict_SetItemString(plpy_dict, "SPIError", PLy_exc_spi_error);
+
+ /*
+ * initialize main module, and add plpy
+ */
+ main_mod = PyImport_AddModule("__main__");
+ main_dict = PyModule_GetDict(main_mod);
+ plpy_mod = PyImport_AddModule("plpy");
+ PyDict_SetItemString(main_dict, "plpy", plpy_mod);
+ if (PyErr_Occurred())
+ elog(ERROR, "Unable to init plpy.");
}
void
PLy_init_safe_interp(void)
{
- PyObject *rmod;
- char *rname = "rexec";
- int i, imax;
+ PyObject *rmod;
+ char *rname = "rexec";
+ int i,
+ imax;
- enter();
+ enter();
- rmod = PyImport_ImportModuleEx(rname, PLy_interp_globals,
- PLy_interp_globals, Py_None);
- if ((rmod == NULL) || (PyErr_Occurred ()))
- PLy_elog(ERROR, "Unable to import %s.", rname);
- PyDict_SetItemString(PLy_interp_globals, rname, rmod);
- PLy_interp_safe = rmod;
+ rmod = PyImport_ImportModuleEx(rname, PLy_interp_globals,
+ PLy_interp_globals, Py_None);
+ if ((rmod == NULL) || (PyErr_Occurred()))
+ PLy_elog(ERROR, "Unable to import %s.", rname);
+ PyDict_SetItemString(PLy_interp_globals, rname, rmod);
+ PLy_interp_safe = rmod;
- imax = sizeof(PLy_importable_modules_list) / sizeof(char *);
- PLy_importable_modules = PyTuple_New(imax);
- for (i = 0; i < imax; i++)
- {
- PyObject *m = PyString_FromString(PLy_importable_modules_list[i]);
- PyTuple_SetItem(PLy_importable_modules, i, m);
- }
+ imax = sizeof(PLy_importable_modules_list) / sizeof(char *);
+ PLy_importable_modules = PyTuple_New(imax);
+ for (i = 0; i < imax; i++)
+ {
+ PyObject *m = PyString_FromString(PLy_importable_modules_list[i]);
+
+ PyTuple_SetItem(PLy_importable_modules, i, m);
+ }
- PLy_interp_safe_globals = PyDict_New();
- if (PLy_interp_safe_globals == NULL)
- PLy_elog(ERROR, "Unable to create shared global dictionary.");
+ PLy_interp_safe_globals = PyDict_New();
+ if (PLy_interp_safe_globals == NULL)
+ PLy_elog(ERROR, "Unable to create shared global dictionary.");
}
@@ -2396,95 +2489,98 @@ PLy_init_safe_interp(void)
static PyObject *PLy_log(int, PyObject *, PyObject *);
PyObject *
-PLy_debug(PyObject *self, PyObject *args)
+PLy_debug(PyObject * self, PyObject * args)
{
- return PLy_log(DEBUG, self, args);
+ return PLy_log(DEBUG, self, args);
}
PyObject *
-PLy_error(PyObject *self, PyObject *args)
+PLy_error(PyObject * self, PyObject * args)
{
- return PLy_log(ERROR, self, args);
+ return PLy_log(ERROR, self, args);
}
PyObject *
-PLy_fatal(PyObject *self, PyObject *args)
+PLy_fatal(PyObject * self, PyObject * args)
{
- return PLy_log(FATAL, self, args);
+ return PLy_log(FATAL, self, args);
}
PyObject *
-PLy_notice(PyObject *self, PyObject *args)
+PLy_notice(PyObject * self, PyObject * args)
{
- return PLy_log(NOTICE, self, args);
+ return PLy_log(NOTICE, self, args);
}
PyObject *
-PLy_log(volatile int level, PyObject *self, PyObject *args)
-{
- DECLARE_EXC();
- PyObject *so;
- char * volatile sv;
-
- enter();
-
- if (args == NULL)
- elog(NOTICE, "plpython, args is NULL in %s", __FUNCTION__);
-
- so = PyObject_Str(args);
- if ((so == NULL) || ((sv = PyString_AsString(so)) == NULL))
- {
- level = ERROR;
- sv = "Unable to parse error message in `plpy.elog'";
- }
-
- /* returning NULL here causes the python interpreter to bail.
- * when control passes back into plpython_*_handler, we
- * check for python exceptions and do the actual elog
- * call. actually PLy_elog.
- */
- if (level == ERROR)
- {
- PyErr_SetString(PLy_exc_error, sv);
- return NULL;
- }
- else if (level >= FATAL)
- {
- PyErr_SetString(PLy_exc_fatal, sv);
- return NULL;
- }
-
- /* ok, this is a NOTICE, or DEBUG message
- *
- * but just in case DON'T long jump out of the interpreter!
- */
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
-
- Py_XDECREF(so);
-
- /* the real error message should already be written into
- * the postgresql log, no? whatever, this shouldn't happen
- * so die hideously.
- */
- elog(FATAL, "plpython: Aiieee, elog threw an unknown exception!");
- return NULL;
- }
-
- elog(level, sv);
-
- RESTORE_EXC();
-
- Py_XDECREF(so);
- Py_INCREF(Py_None);
-
- /* return a legal object so the interpreter will continue on its
- * merry way
- */
- return Py_None;
+PLy_log(volatile int level, PyObject * self, PyObject * args)
+{
+ DECLARE_EXC();
+ PyObject *so;
+ char *volatile sv;
+
+ enter();
+
+ if (args == NULL)
+ elog(NOTICE, "plpython, args is NULL in %s", __FUNCTION__);
+
+ so = PyObject_Str(args);
+ if ((so == NULL) || ((sv = PyString_AsString(so)) == NULL))
+ {
+ level = ERROR;
+ sv = "Unable to parse error message in `plpy.elog'";
+ }
+
+ /*
+ * returning NULL here causes the python interpreter to bail. when
+ * control passes back into plpython_*_handler, we check for python
+ * exceptions and do the actual elog call. actually PLy_elog.
+ */
+ if (level == ERROR)
+ {
+ PyErr_SetString(PLy_exc_error, sv);
+ return NULL;
+ }
+ else if (level >= FATAL)
+ {
+ PyErr_SetString(PLy_exc_fatal, sv);
+ return NULL;
+ }
+
+ /*
+ * ok, this is a NOTICE, or DEBUG message
+ *
+ * but just in case DON'T long jump out of the interpreter!
+ */
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+
+ Py_XDECREF(so);
+
+ /*
+ * the real error message should already be written into the
+ * postgresql log, no? whatever, this shouldn't happen so die
+ * hideously.
+ */
+ elog(FATAL, "plpython: Aiieee, elog threw an unknown exception!");
+ return NULL;
+ }
+
+ elog(level, sv);
+
+ RESTORE_EXC();
+
+ Py_XDECREF(so);
+ Py_INCREF(Py_None);
+
+ /*
+ * return a legal object so the interpreter will continue on its merry
+ * way
+ */
+ return Py_None;
}
@@ -2494,152 +2590,164 @@ PLy_log(volatile int level, PyObject *self, PyObject *args)
static char *PLy_traceback(int *);
static char *PLy_vprintf(const char *fmt, va_list ap);
-static char *PLy_printf(const char *fmt, ...);
+static char *PLy_printf(const char *fmt,...);
void
-PLy_exception_set(PyObject *exc, const char *fmt, ...)
+PLy_exception_set(PyObject * exc, const char *fmt,...)
{
- char buf[1024];
- va_list ap;
+ char buf[1024];
+ va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
- PyErr_SetString(exc, buf);
+ PyErr_SetString(exc, buf);
}
void
PLy_elog(int elevel, const char *fmt,...)
{
- DECLARE_EXC();
- va_list ap;
- char *xmsg, *emsg;
- int xlevel;
+ DECLARE_EXC();
+ va_list ap;
+ char *xmsg,
+ *emsg;
+ int xlevel;
- enter();
+ enter();
- xmsg = PLy_traceback(&xlevel);
+ xmsg = PLy_traceback(&xlevel);
- va_start(ap, fmt);
- emsg = PLy_vprintf(fmt, ap);
- va_end(ap);
+ va_start(ap, fmt);
+ emsg = PLy_vprintf(fmt, ap);
+ va_end(ap);
- SAVE_EXC();
- if (TRAP_EXC())
- {
- RESTORE_EXC();
- mark();
- /* elog called siglongjmp. cleanup, restore and reraise
- */
- PLy_restart_in_progress += 1;
- PLy_free(emsg);
- PLy_free(xmsg);
- RERAISE_EXC();
- }
+ SAVE_EXC();
+ if (TRAP_EXC())
+ {
+ RESTORE_EXC();
+ mark();
+
+ /*
+ * elog called siglongjmp. cleanup, restore and reraise
+ */
+ PLy_restart_in_progress += 1;
+ PLy_free(emsg);
+ PLy_free(xmsg);
+ RERAISE_EXC();
+ }
- if (xmsg)
- {
- elog(elevel, "plpython: %s\n%s", emsg, xmsg);
- PLy_free(xmsg);
- }
- else
- elog(elevel, "plpython: %s", emsg);
- PLy_free(emsg);
+ if (xmsg)
+ {
+ elog(elevel, "plpython: %s\n%s", emsg, xmsg);
+ PLy_free(xmsg);
+ }
+ else
+ elog(elevel, "plpython: %s", emsg);
+ PLy_free(emsg);
- leave();
+ leave();
- RESTORE_EXC();
+ RESTORE_EXC();
}
char *
PLy_traceback(int *xlevel)
{
- PyObject *e, *v, *tb;
- PyObject *eob, *vob = NULL;
- char *vstr, *estr, *xstr = NULL;
-
- enter();
-
- /* get the current exception
- */
- PyErr_Fetch(&e, &v, &tb);
-
- /* oops, no exception, return
- */
- if (e == NULL)
- {
- *xlevel = NOTICE;
- return NULL;
- }
+ PyObject *e,
+ *v,
+ *tb;
+ PyObject *eob,
+ *vob = NULL;
+ char *vstr,
+ *estr,
+ *xstr = NULL;
+
+ enter();
+
+ /*
+ * get the current exception
+ */
+ PyErr_Fetch(&e, &v, &tb);
+
+ /*
+ * oops, no exception, return
+ */
+ if (e == NULL)
+ {
+ *xlevel = NOTICE;
+ return NULL;
+ }
- PyErr_NormalizeException(&e, &v, &tb);
+ PyErr_NormalizeException(&e, &v, &tb);
- eob = PyObject_Str(e);
- if ((v) && ((vob = PyObject_Str(v)) != NULL))
- vstr = PyString_AsString(vob);
- else
- vstr = "Unknown";
+ eob = PyObject_Str(e);
+ if ((v) && ((vob = PyObject_Str(v)) != NULL))
+ vstr = PyString_AsString(vob);
+ else
+ vstr = "Unknown";
- estr = PyString_AsString(eob);
- xstr = PLy_printf("%s: %s", estr, vstr);
+ estr = PyString_AsString(eob);
+ xstr = PLy_printf("%s: %s", estr, vstr);
- Py_DECREF(eob);
- Py_XDECREF(vob);
+ Py_DECREF(eob);
+ Py_XDECREF(vob);
- /* intuit an appropriate error level for based on the exception type
- */
- if ((PLy_exc_error) && (PyErr_GivenExceptionMatches(e, PLy_exc_error)))
- *xlevel = ERROR;
- else if ((PLy_exc_fatal) && (PyErr_GivenExceptionMatches(e, PLy_exc_fatal)))
- *xlevel = FATAL;
- else
- *xlevel = ERROR;
+ /*
+ * intuit an appropriate error level for based on the exception type
+ */
+ if ((PLy_exc_error) && (PyErr_GivenExceptionMatches(e, PLy_exc_error)))
+ *xlevel = ERROR;
+ else if ((PLy_exc_fatal) && (PyErr_GivenExceptionMatches(e, PLy_exc_fatal)))
+ *xlevel = FATAL;
+ else
+ *xlevel = ERROR;
- leave();
+ leave();
- return xstr;
+ return xstr;
}
char *
-PLy_printf(const char *fmt, ...)
+PLy_printf(const char *fmt,...)
{
- va_list ap;
- char *emsg;
+ va_list ap;
+ char *emsg;
- va_start(ap, fmt);
- emsg = PLy_vprintf(fmt, ap);
- va_end(ap);
- return emsg;
+ va_start(ap, fmt);
+ emsg = PLy_vprintf(fmt, ap);
+ va_end(ap);
+ return emsg;
}
char *
PLy_vprintf(const char *fmt, va_list ap)
{
- size_t blen;
- int bchar, tries = 2;
- char *buf;
-
- blen = strlen(fmt) * 2;
- if (blen < 256)
- blen = 256;
- buf = PLy_malloc(blen * sizeof(char));
-
- while (1)
- {
- bchar = vsnprintf(buf, blen, fmt, ap);
- if ((bchar > 0) && (bchar < blen))
- return buf;
- if (tries-- <= 0)
- break;
- if (blen > 0)
- blen = bchar + 1;
- else
- blen *= 2;
- buf = PLy_realloc(buf, blen);
- }
- PLy_free(buf);
- return NULL;
+ size_t blen;
+ int bchar,
+ tries = 2;
+ char *buf;
+
+ blen = strlen(fmt) * 2;
+ if (blen < 256)
+ blen = 256;
+ buf = PLy_malloc(blen * sizeof(char));
+
+ while (1)
+ {
+ bchar = vsnprintf(buf, blen, fmt, ap);
+ if ((bchar > 0) && (bchar < blen))
+ return buf;
+ if (tries-- <= 0)
+ break;
+ if (blen > 0)
+ blen = bchar + 1;
+ else
+ blen *= 2;
+ buf = PLy_realloc(buf, blen);
+ }
+ PLy_free(buf);
+ return NULL;
}
/* python module code
@@ -2652,19 +2760,21 @@ PLy_vprintf(const char *fmt, va_list ap)
void *
PLy_malloc(size_t bytes)
{
- void *ptr = malloc(bytes);
- if (ptr == NULL)
- elog(FATAL, "plpython: Memory exhausted.");
- return ptr;
+ void *ptr = malloc(bytes);
+
+ if (ptr == NULL)
+ elog(FATAL, "plpython: Memory exhausted.");
+ return ptr;
}
void *
PLy_realloc(void *optr, size_t bytes)
{
- void *nptr = realloc(optr, bytes);
- if (nptr == NULL)
- elog(FATAL, "plpython: Memory exhausted.");
- return nptr;
+ void *nptr = realloc(optr, bytes);
+
+ if (nptr == NULL)
+ elog(FATAL, "plpython: Memory exhausted.");
+ return nptr;
}
/* define this away
@@ -2672,5 +2782,5 @@ PLy_realloc(void *optr, size_t bytes)
void
PLy_free(void *ptr)
{
- free(ptr);
+ free(ptr);
}