PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plpy_spi.h File Reference
#include "plpython.h"
#include "utils/resowner.h"
Include dependency graph for plpy_spi.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PLyExceptionEntry
 

Typedefs

typedef struct PLyExceptionEntry PLyExceptionEntry
 

Functions

PyObject * PLy_spi_prepare (PyObject *self, PyObject *args)
 
PyObject * PLy_spi_execute (PyObject *self, PyObject *args)
 
PyObject * PLy_spi_execute_plan (PyObject *ob, PyObject *list, long limit)
 
PyObject * PLy_commit (PyObject *self, PyObject *args)
 
PyObject * PLy_rollback (PyObject *self, PyObject *args)
 
void PLy_spi_subtransaction_begin (MemoryContext oldcontext, ResourceOwner oldowner)
 
void PLy_spi_subtransaction_commit (MemoryContext oldcontext, ResourceOwner oldowner)
 
void PLy_spi_subtransaction_abort (MemoryContext oldcontext, ResourceOwner oldowner)
 

Typedef Documentation

◆ PLyExceptionEntry

Function Documentation

◆ PLy_commit()

PyObject * PLy_commit ( PyObject *  self,
PyObject *  args 
)

Definition at line 446 of file plpy_spi.c.

447{
450
451 PG_TRY();
452 {
453 SPI_commit();
454
455 /* was cleared at transaction end, reset pointer */
456 exec_ctx->scratch_ctx = NULL;
457 }
458 PG_CATCH();
459 {
460 ErrorData *edata;
461 PLyExceptionEntry *entry;
462 PyObject *exc;
463
464 /* Save error info */
465 MemoryContextSwitchTo(oldcontext);
466 edata = CopyErrorData();
468
469 /* was cleared at transaction end, reset pointer */
470 exec_ctx->scratch_ctx = NULL;
471
472 /* Look up the correct exception */
473 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
474 HASH_FIND, NULL);
475
476 /*
477 * This could be a custom error code, if that's the case fallback to
478 * SPIError
479 */
480 exc = entry ? entry->exc : PLy_exc_spi_error;
481 /* Make Python raise the exception */
482 PLy_spi_exception_set(exc, edata);
483 FreeErrorData(edata);
484
485 return NULL;
486 }
487 PG_END_TRY();
488
489 Py_RETURN_NONE;
490}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1818
ErrorData * CopyErrorData(void)
Definition: elog.c:1746
void FlushErrorState(void)
Definition: elog.c:1867
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_CATCH(...)
Definition: elog.h:381
@ HASH_FIND
Definition: hsearch.h:113
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:17
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:365
HTAB * PLy_spi_exceptions
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition: plpy_spi.c:617
void SPI_commit(void)
Definition: spi.c:320
int sqlerrcode
Definition: elog.h:439
PyObject * exc
Definition: plpy_spi.h:21
MemoryContext scratch_ctx
Definition: plpy_main.h:21

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_TRY, PLy_current_execution_context(), PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, PLyExecutionContext::scratch_ctx, SPI_commit(), and ErrorData::sqlerrcode.

◆ PLy_rollback()

PyObject * PLy_rollback ( PyObject *  self,
PyObject *  args 
)

Definition at line 493 of file plpy_spi.c.

494{
497
498 PG_TRY();
499 {
500 SPI_rollback();
501
502 /* was cleared at transaction end, reset pointer */
503 exec_ctx->scratch_ctx = NULL;
504 }
505 PG_CATCH();
506 {
507 ErrorData *edata;
508 PLyExceptionEntry *entry;
509 PyObject *exc;
510
511 /* Save error info */
512 MemoryContextSwitchTo(oldcontext);
513 edata = CopyErrorData();
515
516 /* was cleared at transaction end, reset pointer */
517 exec_ctx->scratch_ctx = NULL;
518
519 /* Look up the correct exception */
520 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
521 HASH_FIND, NULL);
522
523 /*
524 * This could be a custom error code, if that's the case fallback to
525 * SPIError
526 */
527 exc = entry ? entry->exc : PLy_exc_spi_error;
528 /* Make Python raise the exception */
529 PLy_spi_exception_set(exc, edata);
530 FreeErrorData(edata);
531
532 return NULL;
533 }
534 PG_END_TRY();
535
536 Py_RETURN_NONE;
537}
void SPI_rollback(void)
Definition: spi.c:413

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_TRY, PLy_current_execution_context(), PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, PLyExecutionContext::scratch_ctx, SPI_rollback(), and ErrorData::sqlerrcode.

◆ PLy_spi_execute()

PyObject * PLy_spi_execute ( PyObject *  self,
PyObject *  args 
)

Definition at line 150 of file plpy_spi.c.

151{
152 char *query;
153 PyObject *plan;
154 PyObject *list = NULL;
155 long limit = 0;
156
157 if (PyArg_ParseTuple(args, "s|l", &query, &limit))
158 return PLy_spi_execute_query(query, limit);
159
160 PyErr_Clear();
161
162 if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) &&
164 return PLy_spi_execute_plan(plan, list, limit);
165
166 PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan");
167 return NULL;
168}
#define plan(x)
Definition: pg_regress.c:161
PyObject * PLy_exc_error
Definition: plpy_elog.c:15
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:472
bool is_PLyPlanObject(PyObject *ob)
PyObject * PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
Definition: plpy_spi.c:171
static PyObject * PLy_spi_execute_query(char *query, long limit)
Definition: plpy_spi.c:294

References generate_unaccent_rules::args, is_PLyPlanObject(), sort-test::list, plan, PLy_exc_error, PLy_exception_set(), PLy_spi_execute_plan(), and PLy_spi_execute_query().

◆ PLy_spi_execute_plan()

PyObject * PLy_spi_execute_plan ( PyObject *  ob,
PyObject *  list,
long  limit 
)

Definition at line 171 of file plpy_spi.c.

172{
173 volatile int nargs;
174 int rv;
176 volatile MemoryContext oldcontext;
177 volatile ResourceOwner oldowner;
178 PyObject *ret;
179
180 if (list != NULL)
181 {
182 if (!PySequence_Check(list) || PyUnicode_Check(list))
183 {
184 PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
185 return NULL;
186 }
187 nargs = PySequence_Length(list);
188 }
189 else
190 nargs = 0;
191
192 plan = (PLyPlanObject *) ob;
193
194 if (nargs != plan->nargs)
195 {
196 char *sv;
197 PyObject *so = PyObject_Str(list);
198
199 if (!so)
200 PLy_elog(ERROR, "could not execute plan");
201 sv = PLyUnicode_AsString(so);
202 PLy_exception_set_plural(PyExc_TypeError,
203 "Expected sequence of %d argument, got %d: %s",
204 "Expected sequence of %d arguments, got %d: %s",
205 plan->nargs,
206 plan->nargs, nargs, sv);
207 Py_DECREF(so);
208
209 return NULL;
210 }
211
212 oldcontext = CurrentMemoryContext;
213 oldowner = CurrentResourceOwner;
214
215 PLy_spi_subtransaction_begin(oldcontext, oldowner);
216
217 PG_TRY();
218 {
220 MemoryContext tmpcontext;
221 Datum *volatile values;
222 char *volatile nulls;
223 volatile int j;
224
225 /*
226 * Converted arguments and associated cruft will be in this context,
227 * which is local to our subtransaction.
228 */
230 "PL/Python temporary context",
232 MemoryContextSwitchTo(tmpcontext);
233
234 if (nargs > 0)
235 {
236 values = (Datum *) palloc(nargs * sizeof(Datum));
237 nulls = (char *) palloc(nargs * sizeof(char));
238 }
239 else
240 {
241 values = NULL;
242 nulls = NULL;
243 }
244
245 for (j = 0; j < nargs; j++)
246 {
247 PLyObToDatum *arg = &plan->args[j];
248 PyObject *elem;
249
250 elem = PySequence_GetItem(list, j);
251 PG_TRY(2);
252 {
253 bool isnull;
254
255 values[j] = PLy_output_convert(arg, elem, &isnull);
256 nulls[j] = isnull ? 'n' : ' ';
257 }
258 PG_FINALLY(2);
259 {
260 Py_DECREF(elem);
261 }
262 PG_END_TRY(2);
263 }
264
265 MemoryContextSwitchTo(oldcontext);
266
267 rv = SPI_execute_plan(plan->plan, values, nulls,
268 exec_ctx->curr_proc->fn_readonly, limit);
270
271 MemoryContextDelete(tmpcontext);
272 PLy_spi_subtransaction_commit(oldcontext, oldowner);
273 }
274 PG_CATCH();
275 {
276 /* Subtransaction abort will remove the tmpcontext */
277 PLy_spi_subtransaction_abort(oldcontext, oldowner);
278 return NULL;
279 }
280 PG_END_TRY();
281
282 if (rv < 0)
283 {
285 "SPI_execute_plan failed: %s",
287 return NULL;
288 }
289
290 return ret;
291}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define ERROR
Definition: elog.h:39
#define PG_FINALLY(...)
Definition: elog.h:388
int j
Definition: isn.c:73
#define PLy_elog
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurTransactionContext
Definition: mcxt.c:155
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
void * arg
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: plpy_elog.c:486
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:573
static PyObject * PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
Definition: plpy_spi.c:336
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:582
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:565
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
Definition: plpy_typeio.c:120
char * PLyUnicode_AsString(PyObject *unicode)
Definition: plpy_util.c:82
uintptr_t Datum
Definition: postgres.h:69
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
uint64 SPI_processed
Definition: spi.c:44
const char * SPI_result_code_string(int code)
Definition: spi.c:1972
SPITupleTable * SPI_tuptable
Definition: spi.c:45
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:672
PLyProcedure * curr_proc
Definition: plpy_main.h:20

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, arg, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, CurTransactionContext, ERROR, PLyProcedure::fn_readonly, j, sort-test::list, MemoryContextDelete(), MemoryContextSwitchTo(), palloc(), PG_CATCH, PG_END_TRY, PG_FINALLY, PG_TRY, plan, PLy_current_execution_context(), PLy_elog, PLy_exc_spi_error, PLy_exception_set(), PLy_exception_set_plural(), PLy_output_convert(), PLy_spi_execute_fetch_result(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyUnicode_AsString(), SPI_execute_plan(), SPI_processed, SPI_result_code_string(), SPI_tuptable, and values.

Referenced by PLy_plan_execute(), and PLy_spi_execute().

◆ PLy_spi_prepare()

PyObject * PLy_spi_prepare ( PyObject *  self,
PyObject *  args 
)

Definition at line 36 of file plpy_spi.c.

37{
39 PyObject *list = NULL;
40 PyObject *volatile optr = NULL;
41 char *query;
43 volatile MemoryContext oldcontext;
44 volatile ResourceOwner oldowner;
45 volatile int nargs;
46
47 if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list))
48 return NULL;
49
50 if (list && (!PySequence_Check(list)))
51 {
52 PLy_exception_set(PyExc_TypeError,
53 "second argument of plpy.prepare must be a sequence");
54 return NULL;
55 }
56
57 if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
58 return NULL;
59
61 "PL/Python plan context",
63 oldcontext = MemoryContextSwitchTo(plan->mcxt);
64
65 nargs = list ? PySequence_Length(list) : 0;
66
67 plan->nargs = nargs;
68 plan->types = nargs ? palloc0(sizeof(Oid) * nargs) : NULL;
69 plan->args = nargs ? palloc0(sizeof(PLyObToDatum) * nargs) : NULL;
70
71 MemoryContextSwitchTo(oldcontext);
72
73 oldcontext = CurrentMemoryContext;
74 oldowner = CurrentResourceOwner;
75
76 PLy_spi_subtransaction_begin(oldcontext, oldowner);
77
78 PG_TRY();
79 {
80 int i;
81
82 for (i = 0; i < nargs; i++)
83 {
84 char *sptr;
85 Oid typeId;
86 int32 typmod;
87
88 optr = PySequence_GetItem(list, i);
89 if (PyUnicode_Check(optr))
90 sptr = PLyUnicode_AsString(optr);
91 else
92 {
94 (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
95 sptr = NULL; /* keep compiler quiet */
96 }
97
98 /********************************************************
99 * Resolve argument type names and then look them up by
100 * oid in the system cache, and remember the required
101 *information for input conversion.
102 ********************************************************/
103
104 (void) parseTypeString(sptr, &typeId, &typmod, NULL);
105
106 Py_DECREF(optr);
107
108 /*
109 * set optr to NULL, so we won't try to unref it again in case of
110 * an error
111 */
112 optr = NULL;
113
114 plan->types[i] = typeId;
115 PLy_output_setup_func(&plan->args[i], plan->mcxt,
116 typeId, typmod,
117 exec_ctx->curr_proc);
118 }
119
120 pg_verifymbstr(query, strlen(query), false);
121 plan->plan = SPI_prepare(query, plan->nargs, plan->types);
122 if (plan->plan == NULL)
123 elog(ERROR, "SPI_prepare failed: %s",
125
126 /* transfer plan from procCxt to topCxt */
127 if (SPI_keepplan(plan->plan))
128 elog(ERROR, "SPI_keepplan failed");
129
130 PLy_spi_subtransaction_commit(oldcontext, oldowner);
131 }
132 PG_CATCH();
133 {
134 Py_DECREF(plan);
135 Py_XDECREF(optr);
136
137 PLy_spi_subtransaction_abort(oldcontext, oldowner);
138 return NULL;
139 }
140 PG_END_TRY();
141
142 Assert(plan->plan != NULL);
143 return (PyObject *) plan;
144}
#define Assert(condition)
Definition: c.h:815
int32_t int32
Definition: c.h:484
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
int i
Definition: isn.c:72
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: mbutils.c:1556
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
bool parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, Node *escontext)
Definition: parse_type.c:785
PyObject * PLy_plan_new(void)
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:296
unsigned int Oid
Definition: postgres_ext.h:32
int SPI_result
Definition: spi.c:46
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:860
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:976

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, generate_unaccent_rules::args, Assert, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, elog, ereport, errmsg(), ERROR, i, sort-test::list, MemoryContextSwitchTo(), palloc0(), parseTypeString(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), plan, PLy_current_execution_context(), PLy_exception_set(), PLy_output_setup_func(), PLy_plan_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyUnicode_AsString(), SPI_keepplan(), SPI_prepare(), SPI_result, SPI_result_code_string(), and TopMemoryContext.

◆ PLy_spi_subtransaction_abort()

void PLy_spi_subtransaction_abort ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 582 of file plpy_spi.c.

583{
584 ErrorData *edata;
585 PLyExceptionEntry *entry;
586 PyObject *exc;
587
588 /* Save error info */
589 MemoryContextSwitchTo(oldcontext);
590 edata = CopyErrorData();
592
593 /* Abort the inner transaction */
595 MemoryContextSwitchTo(oldcontext);
596 CurrentResourceOwner = oldowner;
597
598 /* Look up the correct exception */
599 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
600 HASH_FIND, NULL);
601
602 /*
603 * This could be a custom error code, if that's the case fallback to
604 * SPIError
605 */
606 exc = entry ? entry->exc : PLy_exc_spi_error;
607 /* Make Python raise the exception */
608 PLy_spi_exception_set(exc, edata);
609 FreeErrorData(edata);
610}
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4788

References CopyErrorData(), CurrentResourceOwner, PLyExceptionEntry::exc, FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, RollbackAndReleaseCurrentSubTransaction(), and ErrorData::sqlerrcode.

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().

◆ PLy_spi_subtransaction_begin()

void PLy_spi_subtransaction_begin ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 565 of file plpy_spi.c.

566{
568 /* Want to run inside function's memory context */
569 MemoryContextSwitchTo(oldcontext);
570}
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4686

References BeginInternalSubTransaction(), and MemoryContextSwitchTo().

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().

◆ PLy_spi_subtransaction_commit()

void PLy_spi_subtransaction_commit ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 573 of file plpy_spi.c.

574{
575 /* Commit the inner transaction, return to outer xact context */
577 MemoryContextSwitchTo(oldcontext);
578 CurrentResourceOwner = oldowner;
579}
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4760

References CurrentResourceOwner, MemoryContextSwitchTo(), and ReleaseCurrentSubTransaction().

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().