PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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

PyObjectPLy_spi_prepare (PyObject *self, PyObject *args)
 
PyObjectPLy_spi_execute (PyObject *self, PyObject *args)
 
PyObjectPLy_spi_execute_plan (PyObject *ob, PyObject *list, long limit)
 
PyObjectPLy_commit (PyObject *self, PyObject *args)
 
PyObjectPLy_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 
)
extern

Definition at line 448 of file plpy_spi.c.

449{
452
453 PG_TRY();
454 {
455 SPI_commit();
456
457 /* was cleared at transaction end, reset pointer */
458 exec_ctx->scratch_ctx = NULL;
459 }
460 PG_CATCH();
461 {
463 PLyExceptionEntry *entry;
464 PyObject *exc;
465
466 /* Save error info */
467 MemoryContextSwitchTo(oldcontext);
470
471 /* was cleared at transaction end, reset pointer */
472 exec_ctx->scratch_ctx = NULL;
473
474 /* Look up the correct exception */
475 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
476 HASH_FIND, NULL);
477
478 /*
479 * This could be a custom error code, if that's the case fallback to
480 * SPIError
481 */
482 exc = entry ? entry->exc : PLy_exc_spi_error;
483 /* Make Python raise the exception */
486
487 return NULL;
488 }
489 PG_END_TRY();
490
492}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
void FreeErrorData(ErrorData *edata)
Definition elog.c:2014
ErrorData * CopyErrorData(void)
Definition elog.c:1942
void FlushErrorState(void)
Definition elog.c:2063
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define PG_CATCH(...)
Definition elog.h:384
@ HASH_FIND
Definition hsearch.h:108
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
PyObject * PLy_exc_spi_error
Definition plpy_elog.c:17
PLyExecutionContext * PLy_current_execution_context(void)
Definition plpy_main.c:336
HTAB * PLy_spi_exceptions
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition plpy_spi.c:619
static int fb(int x)
void SPI_commit(void)
Definition spi.c:321
PyObject * exc
Definition plpy_spi.h:21

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, fb(), 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, and SPI_commit().

◆ PLy_rollback()

PyObject * PLy_rollback ( PyObject self,
PyObject args 
)
extern

Definition at line 495 of file plpy_spi.c.

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

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, fb(), 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, and SPI_rollback().

◆ PLy_spi_execute()

PyObject * PLy_spi_execute ( PyObject self,
PyObject args 
)
extern

Definition at line 152 of file plpy_spi.c.

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

References fb(), is_PLyPlanObject(), 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 
)
extern

Definition at line 173 of file plpy_spi.c.

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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, arg, CurrentMemoryContext, CurrentResourceOwner, CurTransactionContext, ERROR, fb(), j, 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 
)
extern

Definition at line 37 of file plpy_spi.c.

38{
41 PyObject *volatile optr = NULL;
42 char *query;
44 volatile MemoryContext oldcontext;
45 volatile ResourceOwner oldowner;
46 volatile int nargs;
47
48 if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list))
49 return NULL;
50
51 if (list && (!PySequence_Check(list)))
52 {
54 "second argument of plpy.prepare must be a sequence");
55 return NULL;
56 }
57
58 if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
59 return NULL;
60
62 "PL/Python plan context",
64 oldcontext = MemoryContextSwitchTo(plan->mcxt);
65
66 nargs = list ? PySequence_Length(list) : 0;
67
68 plan->nargs = nargs;
69 plan->types = nargs ? palloc0_array(Oid, nargs) : NULL;
70 plan->args = nargs ? palloc0_array(PLyObToDatum, nargs) : NULL;
71
72 MemoryContextSwitchTo(oldcontext);
73
74 oldcontext = CurrentMemoryContext;
75 oldowner = CurrentResourceOwner;
76
77 PLy_spi_subtransaction_begin(oldcontext, oldowner);
78
79 PG_TRY();
80 {
81 int i;
82
83 for (i = 0; i < nargs; i++)
84 {
85 char *sptr;
86 Oid typeId;
87 int32 typmod;
88
89 optr = PySequence_GetItem(list, i);
92 else
93 {
95 (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
96 sptr = NULL; /* keep compiler quiet */
97 }
98
99 /********************************************************
100 * Resolve argument type names and then look them up by
101 * oid in the system cache, and remember the required
102 *information for input conversion.
103 ********************************************************/
104
105 (void) parseTypeString(sptr, &typeId, &typmod, NULL);
106
108
109 /*
110 * set optr to NULL, so we won't try to unref it again in case of
111 * an error
112 */
113 optr = NULL;
114
115 plan->types[i] = typeId;
116 PLy_output_setup_func(&plan->args[i], plan->mcxt,
117 typeId, typmod,
118 exec_ctx->curr_proc);
119 }
120
121 pg_verifymbstr(query, strlen(query), false);
122 plan->plan = SPI_prepare(query, plan->nargs, plan->types);
123 if (plan->plan == NULL)
124 elog(ERROR, "SPI_prepare failed: %s",
126
127 /* transfer plan from procCxt to topCxt */
128 if (SPI_keepplan(plan->plan))
129 elog(ERROR, "SPI_keepplan failed");
130
131 PLy_spi_subtransaction_commit(oldcontext, oldowner);
132 }
133 PG_CATCH();
134 {
137
138 PLy_spi_subtransaction_abort(oldcontext, oldowner);
139 return NULL;
140 }
141 PG_END_TRY();
142
143 Assert(plan->plan != NULL);
144 return (PyObject *) plan;
145}
#define Assert(condition)
Definition c.h:943
int32_t int32
Definition c.h:620
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc0_array(type, count)
Definition fe_memutils.h:92
int i
Definition isn.c:77
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition mbutils.c:1683
MemoryContext TopMemoryContext
Definition mcxt.c:167
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static char * errmsg
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)
unsigned int Oid
int SPI_result
Definition spi.c:47
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition spi.c:861
int SPI_keepplan(SPIPlanPtr plan)
Definition spi.c:977

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CurrentMemoryContext, CurrentResourceOwner, elog, ereport, errmsg, ERROR, fb(), i, MemoryContextSwitchTo(), palloc0_array, 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 
)
extern

Definition at line 584 of file plpy_spi.c.

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

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

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 
)
extern

Definition at line 567 of file plpy_spi.c.

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

References BeginInternalSubTransaction(), fb(), 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 
)
extern

Definition at line 575 of file plpy_spi.c.

576{
577 /* Commit the inner transaction, return to outer xact context */
579 MemoryContextSwitchTo(oldcontext);
580 CurrentResourceOwner = oldowner;
581}
void ReleaseCurrentSubTransaction(void)
Definition xact.c:4819

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().